home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 3 / Gold Medal Software - Volume 3 (Gold Medal) (1994).iso / graphics / 3dvect30.arj / XMODE.ASM < prev    next >
Assembly Source File  |  1993-11-18  |  116KB  |  3,335 lines

  1. ; ========================================================
  2. ; MODEX.ASM - A Complete Mode X Library
  3. ;
  4. ; Version 1.04 Release, 3 May 1993, By Matt Pritchard
  5. ; With considerable input from Michael Abrash
  6. ;
  7. ; The following information is donated to the public domain in
  8. ; the hopes that save other programmers much frustration.
  9. ;
  10. ; If you do use this code in a product, it would be nice if
  11. ; you include a line like "Mode X routines by Matt Pritchard"
  12. ; in the credits.
  13. ;
  14. ; Protected Mode modification by John McCarthy
  15. ; John McCarthy thanks Matt Pritchard for providing this code,
  16. ; and hopes Matt Pritchard is not offended by the changes.
  17. ;
  18. ; ========================================================
  19. ;
  20. ; All of this code is designed to be assembled with MASM 5.10a
  21. ; but TASM 3.0 could be used as well.
  22. ;
  23. ; The routines contained are designed for use in a MEDIUM model
  24. ; program.  All Routines are FAR, and is assumed that a DGROUP
  25. ; data segment exists and that DS will point to it on entry.
  26. ;
  27. ; For all routines, the AX, BX, CX, DX, ES and FLAGS registers
  28. ; will not be preserved, while the DS, BP, SI and DI registers
  29. ; will be preserved.
  30. ;
  31. ; Unless specifically noted, All Parameters are assumed to be
  32. ; "PASSED BY VALUE".  That is, the actual value is placed on
  33. ; the stack.  When a reference is passed it is assumed to be
  34. ; a near pointer to a variable in the DGROUP segment.
  35. ;
  36. ; Routines that return a single 16-Bit integer value will
  37. ; return that value in the AX register.
  38. ;
  39. ; This code will *NOT* run on an 8086/8088 because 80286+
  40. ; specific instructions are used.   If you have an 8088/86
  41. ; and VGA, you can buy an 80386-40 motherboard for about
  42. ; $160 and move into the 90's.
  43. ;
  44. ; JM - revision, this code will *NOT* run on 80286 because of
  45. ; 80368+ code is used (and protected mode).
  46. ;
  47. ; This code is reasonably optimized: Most drawing loops have
  48. ; been unrolled once and memory references are minimized by
  49. ; keeping stuff in registers when possible.
  50. ;
  51. ; Error Trapping varies by Routine.  No Clipping is performed
  52. ; so the caller should verify that all coordinates are valid.
  53. ;
  54. ; Several Macros are used to simplify common 2 or 3 instruction
  55. ; sequences.  Several Single letter Text Constants also
  56. ; simplify common assembler expressions like "WORD PTR".
  57. ;
  58. ; ------------------ Mode X Variations ------------------
  59. ;
  60. ;  Mode #  Screen Size    Max Pages   Aspect Ratio (X:Y)
  61. ;
  62. ;    0      320 x 200      4 Pages         1.2:1
  63. ;    1      320 x 400      2 Pages         2.4:1
  64. ;    2      360 x 200      3 Pages        1.35:1
  65. ;    3      360 x 400      1 Page          2.7:1
  66. ;    4      320 x 240      3 Pages           1:1
  67. ;    5      320 x 480      1 Page            2:1
  68. ;    6      360 x 240      3 Pages       1.125:1
  69. ;    7      360 x 480      1 Page         2.25:1
  70. ;
  71. ; -------------------- The Legal Stuff ------------------
  72. ;
  73. ; No warranty, either written or implied, is made as to
  74. ; the accuracy and usability of this code product.  Use
  75. ; at your own risk.  Batteries not included.  Pepperoni
  76. ; and extra cheese available for an additional charge.
  77. ;
  78. ; ----------------------- The Author --------------------
  79. ;
  80. ; Matt Pritchard is a paid programmer who'd rather be
  81. ; writing games.  He can be reached at: P.O. Box 140264,
  82. ; Irving, TX  75014  USA.  Michael Abrash is a living
  83. ; god, who now works for Bill Gates (Microsoft).
  84. ;
  85. ; -------------------- Revision History -----------------
  86. ; 4-12-93: v1.02 - SET_POINT & READ_POINT now saves DI
  87. ;          SET_MODEX now saves SI
  88. ; 5-3-93:  v1.04 - added LOAD_DAC_REGISTERS and
  89. ;          READ_DAC_REGISTERS.  Expanded CLR Macro
  90. ;          to handle multiple registers
  91. ;
  92. ; Revisions by John McCarthy - sometime throughout June/93:
  93. ;
  94. ; - Protected mode addressing for all routines.
  95. ; - Conditional assembley for routines not wanted by user
  96. ; - Bios text addressing removed - see set_vga_modex
  97. ; - File assembles for protected mode, variables and routines made public
  98. ; - Mode03 routine added to return to DOS mode.  Must be used in conjunction
  99. ;      with TRAN's protected mode header.
  100. ; - Also added routines to turn off the screen to avoid that screen  flicker
  101. ;      when changing into xmode.
  102. ;
  103. ; A note from John McCarthy:
  104. ;
  105. ;  When converting to protected mode, loop's, rep's, stosb's and such
  106. ;  must have the high word of the ecx,edi,esi registers set.  I have tested
  107. ;  the routines now that they have been converted and they seem to all work
  108. ;  fine, but if you find they don't jive, please send me a message/letter and
  109. ;  I will get right on it.
  110. ;
  111. ;  These routines originally came with all kinds of extra files for font
  112. ;  editing, pallet editing, C stuff and demos.  I have only supplied the
  113. ;  critical files from Matt to cut down on .zip file size.
  114. ;
  115.  
  116. x_fill_block    equ 1       ; small routines are automatically included
  117. x_draw_line     equ 1       ; which x mode routines should be included
  118. x_set_point     equ 0       ; when assembled; 1 = enabled
  119. x_read_point    equ 0
  120. x_gprintc       equ 0
  121. x_tgprintc      equ 1
  122. x_set_window    equ 0
  123. x_print_str     equ 0
  124. x_tprint_str    equ 0
  125. x_set_font      equ 0
  126. x_draw_bitmap   equ 0
  127. x_tdraw_bitmap  equ 1
  128. x_copy_page     equ 0
  129. x_copy_bitmap   equ 0
  130.  
  131.            .386p
  132.            jumps
  133.  
  134. code32     segment para public use32
  135.            assume cs:code32, ds:code32
  136.  
  137.            include pmode.inc     ; protected mode externals
  138.            include macros.inc    ; guess...
  139.            include equ.inc       ; list of constants
  140.  
  141. ; xmode routines by matt prichard
  142. ; modified for 386 protected mode by john mccarthy
  143. ; protected mode header courtesy of TRAN
  144.  
  145. ; ===== data tables =====
  146.  
  147. ; bit mask tables for left/right/character masks
  148.  
  149.            public left_clip_mask
  150.            public right_clip_mask
  151.  
  152. left_clip_mask  db 0fh, 0eh, 0ch, 08h
  153. right_clip_mask db 01h, 03h, 07h, 0fh
  154.  
  155. ; bit patterns for converting character fonts
  156.  
  157. char_plane_data db 00h,08h,04h,0ch,02h,0ah,06h,0eh
  158.                 db 01h,09h,05h,0dh,03h,0bh,07h,0fh
  159.  
  160. ; crtc register values for various configurations
  161.  
  162. mode_single_line:       ; crtc setup data for 400/480 line modes
  163.         dw  04009h      ; cell height (1 scan line)
  164.         dw  00014h      ; dword mode off
  165.         dw  0e317h      ; turn on byte mode
  166.         dw  nil         ; end of crtc data for 400/480 line mode
  167.  
  168. mode_double_line:       ; crtc setup data for 200/240 line modes
  169.         dw  04109h      ; cell height (2 scan lines)
  170.         dw  00014h      ; dword mode off
  171.         dw  0e317h      ; turn on byte mode
  172.         dw  nil         ; end of crtc data for 200/240 line mode
  173.  
  174. mode_320_wide:          ; crtc setup data for 320 horz pixels
  175.         dw  05f00h      ; horz total
  176.         dw  04f01h      ; horz displayed
  177.         dw  05002h      ; start horz blanking
  178.         dw  08203h      ; end horz blanking
  179.         dw  05404h      ; start h sync
  180.         dw  08005h      ; end h sync
  181.         dw  nil         ; end of crtc data for 320 horz pixels
  182.  
  183. mode_360_wide:          ; crtc setup data for 360 horz pixels
  184.         dw  06b00h      ; horz total
  185.         dw  05901h      ; horz displayed
  186.         dw  05a02h      ; start horz blanking
  187.         dw  08e03h      ; end horz blanking
  188.         dw  05e04h      ; start h sync
  189.         dw  08a05h      ; end h sync
  190.         dw  nil         ; end of crtc data for 360 horz pixels
  191.  
  192. mode_200_tall:
  193. mode_400_tall:          ; crtc setup data for 200/400 line modes
  194.         dw  0bf06h      ; vertical total
  195.         dw  01f07h      ; overflow
  196.         dw  09c10h      ; v sync start
  197.         dw  08e11h      ; v sync end/prot cr0 cr7
  198.         dw  08f12h      ; vertical displayed
  199.         dw  09615h      ; v blank start
  200.         dw  0b916h      ; v blank end
  201.         dw  nil         ; end of crtc data for 200/400 lines
  202.  
  203. mode_240_tall:
  204. mode_480_tall:          ; crtc setup data for 240/480 line modes
  205.         dw  00d06h      ; vertical total
  206.         dw  03e07h      ; overflow
  207.         dw  0ea10h      ; v sync start
  208.         dw  08c11h      ; v sync end/prot cr0 cr7
  209.         dw  0df12h      ; vertical displayed
  210.         dw  0e715h      ; v blank start
  211.         dw  00616h      ; v blank end
  212.         dw  nil         ; end of crtc data for 240/480 lines
  213.  
  214. ; table of display mode tables
  215.  
  216. mode_table:
  217.         dd  o mode_320x200, o mode_320x400
  218.         dd  o mode_360x200, o mode_360x400
  219.         dd  o mode_320x240, o mode_320x480
  220.         dd  o mode_360x240, o mode_360x480
  221.  
  222. ; table of display mode components
  223.  
  224. mode_320x200:           ; data for 320 by 200 pixels
  225.  
  226.         db  063h        ; 400 scan lines & 25 mhz clock
  227.         db  4           ; maximum of 4 pages
  228.         dw  320, 200    ; displayed pixels (x,y)
  229.         dw  1302, 816   ; max possible x and y sizes
  230.  
  231.         dd  o mode_320_wide, o mode_200_tall
  232.         dd  o mode_double_line, nil
  233.  
  234. mode_320x400:           ; data for 320 by 400 pixels
  235.  
  236.         db  063h        ; 400 scan lines & 25 mhz clock
  237.         db  2           ; maximum of 2 pages
  238.         dw  320, 400    ; displayed pixels x,y
  239.         dw  648, 816    ; max possible x and y sizes
  240.  
  241.         dd  o mode_320_wide, o mode_400_tall
  242.         dd  o mode_single_line, nil
  243.  
  244. mode_360x240:           ; data for 360 by 240 pixels
  245.  
  246.         db  0e7h        ; 480 scan lines & 28 mhz clock
  247.         db  3           ; maximum of 3 pages
  248.         dw  360, 240    ; displayed pixels x,y
  249.         dw  1092, 728   ; max possible x and y sizes
  250.  
  251.         dd  o mode_360_wide, o mode_240_tall
  252.         dd  o mode_double_line , nil
  253.  
  254. mode_360x480:           ; data for 360 by 480 pixels
  255.  
  256.         db  0e7h        ; 480 scan lines & 28 mhz clock
  257.         db  1           ; only 1 page possible
  258.         dw  360, 480    ; displayed pixels x,y
  259.         dw  544, 728    ; max possible x and y sizes
  260.  
  261.         dd  o mode_360_wide, o mode_480_tall
  262.         dd  o mode_single_line , nil
  263.  
  264. mode_320x240:           ; data for 320 by 240 pixels
  265.  
  266.         db  0e3h        ; 480 scan lines & 25 mhz clock
  267.         db  3           ; maximum of 3 pages
  268.         dw  320, 240    ; displayed pixels x,y
  269.         dw  1088, 818   ; max possible x and y sizes
  270.  
  271.         dd  o mode_320_wide, o mode_240_tall
  272.         dd  o mode_double_line, nil
  273.  
  274. mode_320x480:           ; data for 320 by 480 pixels
  275.  
  276.         db  0e3h        ; 480 scan lines & 25 mhz clock
  277.         db  1           ; only 1 page possible
  278.         dw  320, 480    ; displayed pixels x,y
  279.         dw  540, 818    ; max possible x and y sizes
  280.  
  281.         dd  o mode_320_wide, o mode_480_tall
  282.         dd  o mode_single_line, nil
  283.  
  284. mode_360x200:           ; data for 360 by 200 pixels
  285.  
  286.         db  067h        ; 400 scan lines & 28 mhz clock
  287.         db  3           ; maximum of 3 pages
  288.         dw  360, 200    ; displayed pixels (x,y)
  289.         dw  1302, 728   ; max possible x and y sizes
  290.  
  291.         dd  o mode_360_wide, o mode_200_tall
  292.         dd  o mode_double_line, nil
  293.  
  294. mode_360x400:           ; data for 360 by 400 pixels
  295.  
  296.         db  067h        ; 400 scan lines & 28 mhz clock
  297.         db  1           ; maximum of 1 pages
  298.         dw  360, 400    ; displayed pixels x,y
  299.         dw  648, 816    ; max possible x and y sizes
  300.  
  301.         dd  o mode_360_wide, o mode_400_tall
  302.         dd  o mode_single_line, nil
  303.  
  304. mode_data_table struc
  305.     m_miscr         db  ?       ; value of misc_output register
  306.     m_pages         db  ?       ; maximum possible # of pages
  307.     m_xsize         dw  ?       ; x size displayed on screen
  308.     m_ysize         dw  ?       ; y size displayed on screen
  309.     m_xmax          dw  ?       ; maximum possible x size
  310.     m_ymax          dw  ?       ; maximum possible y size
  311.     m_crtc          dd  ?       ; table of crtc register values
  312. mode_data_table ends
  313.  
  314. ; specific x mode data table format...
  315.  
  316. screen_width    dw  0        ; actual width of a line in bytes
  317. screen_height   dw  0        ; actual vertical height in pixels
  318.  
  319. last_page       dw  0        ; # of display pages
  320. page_addr       dd  4 dup (0) ; offsets to start of each page
  321.  
  322. page_size       dw  0        ; size of page in addr bytes
  323.  
  324. display_page    dw  0        ; page # currently displayed
  325. active_page     dw  0        ; page # currently active
  326.  
  327. current_page    dd  0        ; address of current page
  328.  
  329. current_xoffset dw  0        ; current display x offset
  330. current_yoffset dw  0        ; current display y offset
  331.  
  332. current_moffset dd  0        ; current start offset
  333.  
  334. max_xoffset     dw  0        ; current display x offset
  335. max_yoffset     dw  0        ; current display y offset
  336.  
  337. charset_low     dd  0        ; far ptr to char set: 0-127
  338. charset_hi      dd  0        ; far ptr to char set: 128-255
  339.  
  340.         public  screen_width
  341.         public  screen_height
  342.  
  343.         public  last_page
  344.         public  page_addr
  345.  
  346.         public  page_size
  347.  
  348.         public  display_page
  349.         public  active_page
  350.  
  351.         public  current_page
  352.  
  353.         public  current_xoffset
  354.         public  current_yoffset
  355.  
  356.         public  current_moffset
  357.  
  358.         public  max_xoffset
  359.         public  max_yoffset
  360.  
  361.         public  charset_low
  362.         public  charset_hi
  363.  
  364.     ; ===== mode x setup routines =====
  365.  
  366. ;======================================================
  367. ;set_vga_modex% (modetype%, maxxpos%, maxypos%, pages%)
  368. ;======================================================
  369. ;
  370. ; sets up the specified version of mode x.  allows for
  371. ; the setup of multiple video pages, and a virtual
  372. ; screen which can be larger than the displayed screen
  373. ; (which can then be scrolled a pixel at a time)
  374. ;
  375. ; entry: modetype = desired screen resolution (0-7)
  376. ;
  377. ;     0 =  320 x 200, 4 pages max,   1.2:1 aspect ratio
  378. ;     1 =  320 x 400, 2 pages max,   2.4:1 aspect ratio
  379. ;     2 =  360 x 200, 3 pages max,  1.35:1 aspect ratio
  380. ;     3 =  360 x 400, 1 page  max,   2.7:1 aspect ratio
  381. ;     4 =  320 x 240, 3 pages max,     1:1 aspect ratio
  382. ;     5 =  320 x 480, 1 page  max,     2:1 aspect ratio
  383. ;     6 =  360 x 240, 3 pages max, 1.125:1 aspect ratio
  384. ;     7 =  360 x 480, 1 page  max,  2.25:1 aspect ratio
  385. ;
  386. ;        maxxpos = the desired virtual screen width
  387. ;        maxypos = the desired virtual screen height
  388. ;        pages   = the desired # of video pages
  389. ;
  390. ; exit:  ax = success flag:   0 = failure / -1= success
  391. ;
  392.  
  393. svm_stack   struc
  394.     svm_table   dd  ?   ; offset of mode info table
  395.                 dd  ?x3 ; edi, esi, ebp
  396.                 dd  ?   ; caller
  397.     svm_pages   dw  ?   ; # of screen pages desired
  398.     svm_ysize   dw  ?   ; vertical screen size desired
  399.     svm_xsize   dw  ?   ; horizontal screen size desired
  400.     svm_mode    dw  ?   ; display resolution desired
  401. svm_stack   ends
  402.  
  403.     public  set_vga_modex
  404.  
  405. set_vga_modex:
  406.     push    ebp esi edi         ; preserve important registers
  407.     sub     esp, 4              ; allocate workspace
  408.     mov     ebp, esp            ; set up stack frame
  409.  
  410. ; check legality of mode request....
  411.  
  412.     movzx   ebx, [ebp].svm_mode ; get requested mode #
  413.  
  414.     cmp     bx, num_modes       ; is it 0..7?
  415.     jae     @svm_badmodesetup   ; if not, error out
  416.  
  417.     shl     bx, 2                  ; scale bx
  418.     mov     esi, d mode_table[ebx] ; si -> mode info
  419.     mov     [ebp].svm_table, esi   ; save ptr for later use
  420.  
  421. ; check # of requested display pages
  422.  
  423.     mov     cx, [ebp].svm_pages ; get # of requested pages
  424.  
  425.     clr     ch                  ; set hi word = 0!
  426.     cmp     cl, [esi].m_pages   ; check # pages for mode
  427.  
  428.     ja      @svm_badmodesetup   ; report error if too many pages
  429.     jcxz    @svm_badmodesetup   ; report error if 0 pages
  430.  
  431. ; check validity of x size
  432.  
  433.     and     [ebp].svm_xsize, 0fff8h  ; x size mod 8 must = 0
  434.  
  435.     mov     ax, [ebp].svm_xsize ; get logical screen width
  436.  
  437.     cmp     ax, [esi].m_xsize   ; check against displayed x
  438.     jb      @svm_badmodesetup   ; report error if too small
  439.     cmp     ax, [esi].m_xmax    ; check against max x
  440.     ja      @svm_badmodesetup   ; report error if too big
  441.  
  442. ; check validity of y size
  443.  
  444.     mov     bx, [ebp].svm_ysize ; get logical screen height
  445.     cmp     bx, [esi].m_ysize   ; check against displayed y
  446.     jb      @svm_badmodesetup   ; report error if too small
  447.     cmp     bx, [esi].m_ymax    ; check against max y
  448.     ja      @svm_badmodesetup   ; report error if too big
  449.  
  450. ; enough memory to fit it all?
  451.  
  452.     shr     ax, 2               ; # of bytes:line = xsize/4
  453.     mul     cx                  ; ax = bytes/line * pages
  454.     mul     bx                  ; dx:ax = total vga mem needed
  455.     jno     @svm_continue       ; exit if total size > 256k
  456.  
  457.     dec     dx                  ; was it exactly 256k???
  458.     or      dx, ax              ; (dx = 1, ax = 0000)
  459.     jz      @svm_continue       ; if so, it's valid...
  460.  
  461. @svm_badmodesetup:
  462.  
  463.     clr     ax                  ; return value = false
  464.     jmp     @svm_exit           ; normal exit
  465.  
  466. @svm_continue:
  467.  
  468.     mov     v86r_ax,13h         ; start with mode 13h
  469.     mov     al,10h              ; bios int 10h
  470.     int     33h                 ; let v86 handler call bios int 10h
  471.  
  472.     call turn_screen_off        ; prevent flicker
  473.  
  474.     out_16  sc_index, chain4_off        ; disable chain 4 mode
  475.     out_16  sc_index, async_reset       ; (a)synchronous reset
  476.     out_8   misc_output, [esi].m_miscr  ; set new timing/size
  477.     out_16  sc_index, sequ_restart      ; restart sequencer ...
  478.  
  479.     out_8   crtc_index, 11h     ; select vert retrace end register
  480.     inc     dx                  ; point to data
  481.     in      al, dx              ; get value, bit 7 = protect
  482.     and     al, 7fh             ; mask out write protect
  483.     out     dx, al              ; and send it back
  484.  
  485.     mov     dx, crtc_index      ; vga crtc registers
  486.     add     esi, m_crtc         ; si -> crtc parameter data
  487.  
  488. ; load tables of crtc parameters from list of tables
  489.  
  490. @svm_setup_table:
  491.  
  492.     mov     edi, [esi]          ; get pointer to crtc data tbl
  493.     add     esi, 4              ; point to next ptr entry
  494.     or      edi, edi            ; a nil ptr means that we have
  495.     jz      @svm_set_data       ; finished crtc programming
  496.  
  497. @svm_setup_crtc:
  498.     mov     ax, [edi]           ; get crtc data from table
  499.     add     edi, 2              ; advance pointer
  500.     or      ax, ax              ; at end of data table?
  501.     jz      @svm_setup_table    ; if so, exit & get next table
  502.  
  503.     out     dx, ax              ; reprogram vga crtc reg
  504.     jmp     s @svm_setup_crtc   ; process next table entry
  505.  
  506. ; initialize page & scroll info, edi = 0
  507.  
  508. @svm_set_data:
  509.     mov     display_page, di    ; display page = 0
  510.     mov     active_page, di     ; active page = 0
  511.     mov     current_xoffset, di ; horz scroll index = 0
  512.     mov     current_yoffset, di ; vert scroll index = 0
  513.     mov     current_moffset,edi ; memory scroll index = 0
  514.  
  515.     @rlp    esi, vga_segment    ; segment for vga memory
  516.     mov     current_page, esi
  517.  
  518. ; set logical screen width, x scroll and our data
  519.  
  520.     mov     esi, [ebp].svm_table ; get saved ptr to mode info
  521.     mov     ax, [ebp].svm_xsize ; get display width
  522.  
  523.     mov     cx, ax              ; cx = logical width
  524.     sub     cx, [esi].m_xsize   ; cx = max x scroll value
  525.     mov     max_xoffset, cx     ; set maximum x scroll
  526.  
  527.     shr     ax, 2               ; bytes = pixels / 4
  528.     mov     screen_width, ax    ; save width in pixels
  529.  
  530.     shr     ax, 1               ; offset value = bytes / 2
  531.     mov     ah, 13h             ; crtc offset register index
  532.     xchg    al, ah              ; switch format for out
  533.     out     dx, ax              ; set vga crtc offset reg
  534.  
  535. ; setup data table, y scroll, misc for other routines
  536.  
  537.     mov     ax, [ebp].svm_ysize ; get logical screen height
  538.  
  539.     mov     cx, ax              ; cx = logical height
  540.     sub     bx, [esi].m_ysize   ; cx = max y scroll value
  541.     mov     max_yoffset, cx     ; set maximum y scroll
  542.  
  543.     mov     screen_height, ax   ; save height in pixels
  544.     mul     screen_width        ; ax = page size in bytes,
  545.     mov     page_size, ax       ; save page size
  546.  
  547.     mov     cx, [ebp].svm_pages ; get # of pages
  548.     mov     last_page, cx       ; save # of pages
  549.  
  550.     clr     bx                  ; page # = 0
  551.     @rlp    edx, vga_segment    ; page 0 offset = 0a0000h
  552.     movzx   eax,ax              ; clear top word of eax
  553.     movzx   ebx,bx
  554.  
  555. @svm_set_pages:
  556.  
  557.     mov     page_addr[ebx], edx ; set page #(bx) offset
  558.     add     bx, 4               ; page#++
  559.     add     edx, eax            ; compute addr of next page
  560.     loopx   cx, @svm_set_pages  ; loop until all pages set
  561.  
  562. ; clear vga memory
  563.  
  564.     out_16  sc_index, all_planes_on ; select all planes
  565.     mov     edi, current_page   ; -> start of vga memory
  566.  
  567.     clr     ax                  ; ax = 0
  568.     cld                         ; block xfer forwards
  569.     mov     ecx, 8000h          ; 32k * 4 * 2 = 256k
  570.     rep     stosw               ; clear dat memory!
  571.  
  572. ; setup font pointers, in protected mode.  you must shl 8 then add but
  573. ; i don't know how to correctly convert segmented code to flat memory.
  574. ;
  575. ;   mov     v86r_bh, rom_8x8_lo    ; ask for 8x8 font, 0-127
  576. ;   mov     v86r_ax, get_char_ptr  ; service to get pointer
  577. ;   mov     al,10h
  578. ;   int     33h                 ; call vga bios through v86 handler
  579. ;
  580. ;   mov     charset_low, bp     ; save char set offset
  581. ;   mov     charset_low+2, es   ; save char set segment
  582. ;
  583. ;   mov     v86r_bh, rom_8x8_hi    ; ask for 8x8 font, 128-255
  584. ;   mov     v86r_ax, get_char_ptr  ; service to get pointer
  585. ;   mov     al,10h
  586. ;   int     33h                 ; call vga bios
  587. ;
  588. ;   mov     charset_hi, bp      ; save char set offset
  589. ;   mov     charset_hi+2, es    ; save char set segment
  590.  
  591.     call turn_screen_on         ; prevent flicker
  592.  
  593.     mov     ax, true            ; return success code
  594.  
  595. @svm_exit:
  596.     add     esp, 4              ; deallocate workspace
  597.     pop     edi esi ebp         ; restore saved registers
  598.     ret     8                   ; exit & clean up stack
  599.  
  600. ;==================
  601. ;set_modex% (mode%)
  602. ;==================
  603. ;
  604. ; quickie mode set - sets up mode x to default configuration
  605. ;
  606. ; entry: modetype = desired screen resolution (0-7)
  607. ;        (see set_vga_modex for list)
  608. ;
  609. ; exit:  ax = success flag:   0 = failure / -1= success
  610. ;
  611.  
  612. sm_stack    struc
  613.                 dd  ?,? ; ebp, esi
  614.                 dd  ?   ; caller
  615.     sm_mode     dw  ?   ; desired screen resolution
  616. sm_stack    ends
  617.  
  618.     public  set_modex
  619.  
  620. set_modex:
  621.     push    ebp esi             ; preserve important registers
  622.     mov     ebp, esp            ; set up stack frame
  623.  
  624.     clr     ax                  ; assume failure
  625.     movzx   ebx, [ebp].sm_mode  ; get desired mode #
  626.     cmp     bx, num_modes       ; is it a valid mode #?
  627.     jae     @smx_exit           ; if not, don't bother
  628.  
  629.     push    bx                  ; push mode parameter
  630.  
  631.     shl     bx, 2                 ; scale bx to dword indexer
  632.     mov     esi, d mode_table[ebx] ; esi -> mode info
  633.  
  634.     push    [esi].m_xsize       ; push default x size
  635.     push    [esi].m_ysize       ; push default y size
  636.     mov     al, [esi].m_pages   ; get default # of pages
  637.     clr     ah                  ; hi byte = 0
  638.     push    ax                  ; push # pages
  639.  
  640.     call    set_vga_modex       ; set up mode x!
  641.  
  642. @smx_exit:
  643.     pop     esi ebp             ; restore registers
  644.     ret     2                   ; exit & clean up stack
  645.  
  646. ; ===== basic graphics primitives =====
  647.  
  648. ;============================
  649. ;clear_vga_screen (colornum%)
  650. ;============================
  651. ;
  652. ; clears the active display page
  653. ;
  654. ; entry: colornum = color value to fill the page with
  655. ;
  656. ; exit:  no meaningful values returned
  657. ;
  658.  
  659. cvs_stack   struc
  660.                 dd  ?,? ; edi, ebp
  661.                 dd  ?   ; caller
  662.     cvs_color   db  ?,? ; color to set screen to
  663. cvs_stack   ends
  664.  
  665.     public  clear_vga_screen
  666.  
  667. clear_vga_screen:
  668.  
  669.     push    ebp edi             ; preserve important registers
  670.     mov     ebp, esp            ; set up stack frame
  671.  
  672.     out_16  sc_index, all_planes_on ; select all planes
  673.     mov     edi, current_page   ; point to active vga page
  674.  
  675.     mov     al, [ebp].cvs_color ; get color
  676.     mov     ah, al              ; copy for dword write
  677.     mov     bp,ax
  678.     shl     eax,16
  679.     mov     ax,bp
  680.     cld                         ; block fill forwards
  681.  
  682.     movzx   ecx, page_size      ; get size of page
  683.     shr     cx, 2               ; divide by 4 for dwords
  684.     rep     stosd               ; block fill vga memory
  685.  
  686.     pop     edi ebp             ; restore saved registers
  687.     ret     2                   ; exit & clean up stack
  688.  
  689. ;===================================
  690. ;set_point (xpos%, ypos%, colornum%)
  691. ;===================================
  692. ;
  693. ; plots a single pixel on the active display page
  694. ;
  695. ; entry: xpos     = x position to plot pixel at
  696. ;        ypos     = y position to plot pixel at
  697. ;        colornum = color to plot pixel with
  698. ;
  699. ; exit:  no meaningful values returned
  700. ;
  701.  
  702. sp_stack    struc
  703.                 dd  ?,? ; ebp, edi
  704.                 dd  ?   ; caller
  705.     setp_color  db  ?,? ; color of point to plot
  706.     setp_ypos   dw  ?   ; y pos of point to plot
  707.     setp_xpos   dw  ?   ; x pos of point to plot
  708. sp_stack    ends
  709.  
  710.         public set_point
  711.  
  712. set_point:
  713.  
  714.     push    ebp edi             ; preserve registers
  715.     mov     ebp, esp            ; set up stack frame
  716.  
  717.     mov     edi, current_page   ; point to active vga page
  718.  
  719.     mov     ax, [ebp].setp_ypos ; get line # of pixel
  720.     mul     screen_width        ; get offset to start of line
  721.  
  722.     clr     ebx                 ; wipe high word
  723.     mov     bx, [ebp].setp_xpos ; get xpos
  724.     mov     cx, bx              ; copy to extract plane # from
  725.     shr     bx, 2               ; x offset (bytes) = xpos/4
  726.     add     bx, ax              ; offset = width*ypos + xpos/4
  727.  
  728.     mov     ax, map_mask_plane1 ; map mask & plane select register
  729.     and     cl, plane_bits      ; get plane bits
  730.     shl     ah, cl              ; get plane select value
  731.     out_16  sc_index, ax        ; select plane
  732.  
  733.     mov     al,[ebp].setp_color ; get pixel color
  734.     mov     [edi+ebx], al       ; draw pixel
  735.  
  736.     pop     edi ebp             ; restore saved registers
  737.     ret     6                   ; exit and clean up stack
  738.  
  739. ;==========================
  740. ;read_point% (xpos%, ypos%)
  741. ;==========================
  742. ;
  743. ; read the color of a pixel from the active display page
  744. ;
  745. ; entry: xpos = x position of pixel to read
  746. ;        ypos = y position of pixel to read
  747. ;
  748. ; exit:  ax   = color of pixel at (xpos, ypos)
  749. ;
  750.  
  751. rp_stack    struc
  752.             dd  ?,? ; ebp, edi
  753.             dd  ?   ; caller
  754.     rp_ypos dw  ?   ; y pos of point to read
  755.     rp_xpos dw  ?   ; x pos of point to read
  756. rp_stack    ends
  757.  
  758.         public  read_point
  759.  
  760. read_point:
  761.  
  762.     push    ebp edi             ; preserve registers
  763.     mov     ebp, esp            ; set up stack frame
  764.  
  765.     mov     edi, current_page   ; point to active vga page
  766.  
  767.     mov     ax, [ebp].rp_ypos   ; get line # of pixel
  768.     mul     screen_width        ; get offset to start of line
  769.  
  770.     clr     ebx                 ; wipe high word
  771.     mov     bx, [ebp].rp_xpos   ; get xpos
  772.     mov     cx, bx
  773.     shr     bx, 2               ; x offset (bytes) = xpos/4
  774.     add     bx, ax              ; offset = width*ypos + xpos/4
  775.  
  776.     mov     al, read_map        ; gc read mask register
  777.     mov     ah, cl              ; get xpos
  778.     and     ah, plane_bits      ; & mask out plane #
  779.     out_16  gc_index, ax        ; select plane to read in
  780.  
  781.     clr     eax                 ; clear return value hi byte
  782.     mov     al, [edi+ebx]       ; get color of pixel
  783.  
  784.     pop     edi ebp             ; restore saved registers
  785.     ret     4                   ; exit and clean up stack
  786.  
  787.     if x_fill_block eq 1
  788.  
  789. ;======================================================
  790. ;fill_block (xpos1%, ypos1%, xpos2%, ypos2%, colornum%)
  791. ;======================================================
  792. ;
  793. ; fills a rectangular block on the active display page
  794. ;
  795. ; entry: xpos1    = left x position of area to fill
  796. ;        ypos1    = top y position of area to fill
  797. ;        xpos2    = right x position of area to fill
  798. ;        ypos2    = bottom y position of area to fill
  799. ;        colornum = color to fill area with
  800. ;
  801. ; exit:  no meaningful values returned
  802. ;
  803.  
  804. fb_stack    struc
  805.                 dd  ?x3 ; edi, esi, ebp
  806.                 dd  ?   ; caller
  807.     fb_color    db  ?,? ; fill color
  808.     fb_ypos2    dw  ?   ; y pos of lower right pixel
  809.     fb_xpos2    dw  ?   ; x pos of lower right pixel
  810.     fb_ypos1    dw  ?   ; y pos of upper left pixel
  811.     fb_xpos1    dw  ?   ; x pos of upper left pixel
  812. fb_stack    ends
  813.  
  814.         public    fill_block
  815.  
  816. fill_block:
  817.  
  818.     push    ebp esi edi         ; preserve important registers
  819.     mov     ebp, esp            ; set up stack frame
  820.  
  821.     mov     edi, current_page   ; point to active vga page
  822.     cld                         ; direction flag = forward
  823.  
  824.     out_8   sc_index, map_mask  ; set up for plane select
  825.  
  826. ; validate pixel coordinates
  827. ; if necessary, swap so x1 <= x2, y1 <= y2
  828.  
  829.     clr     eax
  830.     clr     ecx
  831.     mov     ax, [ebp].fb_ypos1  ; ax = y1   is y1< y2?
  832.     mov     bx, [ebp].fb_ypos2  ; bx = y2
  833.     cmp     ax, bx
  834.     jle     @fb_noswap1
  835.  
  836.     mov     [ebp].fb_ypos1, bx  ; swap y1 and y2 and save y1
  837.     xchg    ax, bx              ; on stack for future use
  838.  
  839. @fb_noswap1:
  840.     sub     bx, ax              ; get y width
  841.     inc     bx                  ; add 1 to avoid 0 value
  842.     mov     [ebp].fb_ypos2, bx  ; save in ypos2
  843.  
  844.     mul     screen_width        ; mul y1 by bytes per line
  845.     add     edi, eax            ; di = start of line y1
  846.  
  847.     mov     ax, [ebp].fb_xpos1  ; check x1 <= x2
  848.     mov     bx, [ebp].fb_xpos2  ;
  849.     cmp     ax, bx
  850.     jle     @fb_noswap2         ; skip ahead if ok
  851.  
  852.     mov     [ebp].fb_xpos2, ax  ; swap x1 and x2 and save x2
  853.     xchg    ax, bx              ; on stack for future use
  854.  
  855. ; all our input values are in  order,  now  determine
  856. ; how many full "bands" 4 pixels wide (aligned) there
  857. ; are, and if there are partial bands (<4 pixels)  on
  858. ; the left and right edges.
  859.  
  860. @fb_noswap2:
  861.     movzx   edx, ax             ; dx = x1 (pixel position)
  862.     shr     edx, 2              ; dx/4 = bytes into line
  863.     add     edi, edx            ; di = addr of upper-left corner
  864.  
  865.     movzx   ecx, bx             ; cx = x2 (pixel position)
  866.     shr     cx, 2               ; cx/4 = bytes into line
  867.  
  868.     cmp     dx, cx              ; start and end in same band?
  869.     jne     @fb_normal          ; if not, check for l & r edges
  870.     jmp     @fb_one_band_only   ; if so, then special processing
  871.  
  872. @fb_normal:
  873.     sub     cx, dx              ; cx = # bands -1
  874.     movzx   esi, ax             ; si = plane#(x1)
  875.     and     si, plane_bits      ; if left edge is aligned then
  876.     jz      @fb_l_plane_flush   ; no special processing..
  877.  
  878. ; draw "left edge" vertical strip of 1-3 pixels...
  879.  
  880.     out_8   sc_data, left_clip_mask[esi] ; set left edge plane mask
  881.  
  882.     mov     esi, edi            ; si = copy of start addr (ul)
  883.  
  884.     mov     dx, [ebp].fb_ypos2  ; get # of lines to draw
  885.     mov     al, [ebp].fb_color  ; get fill color
  886.     movzx   ebx, screen_width   ; get vertical increment value
  887.  
  888. @fb_left_loop:
  889.     mov     [esi], al           ; fill in left edge pixels
  890.     add     esi, ebx            ; point to next line (below)
  891.     loopjz  dx, @fb_left_cont   ; exit loop if all lines drawn
  892.  
  893.     mov     [esi], al           ; fill in left edge pixels
  894.     add     esi, ebx            ; point to next line (below)
  895.     loopx   dx, @fb_left_loop   ; loop until left strip is drawn
  896.  
  897. @fb_left_cont:
  898.  
  899.     inc     edi                 ; point to middle (or right) block
  900.     dec     cx                  ; reset cx instead of jmp @fb_right
  901.  
  902. @fb_l_plane_flush:
  903.     inc     cx                  ; add in left band to middle block
  904.  
  905. ; di = addr of 1st middle pixel (band) to fill
  906. ; cx = # of bands to fill -1
  907.  
  908. @fb_right:
  909.     movzx   esi, [ebp].fb_xpos2 ; get xpos2
  910.     and     si, plane_bits      ; get plane values
  911.     cmp     si, 0003            ; plane = 3?
  912.     je      @fb_r_edge_flush    ; hey, add to middle
  913.  
  914. ; draw "right edge" vertical strip of 1-3 pixels...
  915.  
  916.     out_8   sc_data, right_clip_mask[esi]    ; right edge plane mask
  917.  
  918.     mov     esi, edi            ; get addr of left edge
  919.     add     esi, ecx            ; add width-1 (bands)
  920.     dec     esi                 ; to point to top of right edge
  921.  
  922.     mov     dx, [ebp].fb_ypos2  ; get # of lines to draw
  923.     mov     al, [ebp].fb_color  ; get fill color
  924.     movzx   ebx, screen_width   ; get vertical increment value
  925.  
  926. @fb_right_loop:
  927.     mov     [esi], al           ; fill in right edge pixels
  928.     add     esi, ebx            ; point to next line (below)
  929.     loopjz  dx, @fb_right_cont  ; exit loop if all lines drawn
  930.  
  931.     mov     [esi], al            ; fill in right edge pixels
  932.     add     esi, ebx            ; point to next line (below)
  933.     loopx   dx, @fb_right_loop  ; loop until left strip is drawn
  934.  
  935. @fb_right_cont:
  936.  
  937.     dec     cx                  ; minus 1 for middle bands
  938.     jz      @fb_exit            ; uh.. no middle bands...
  939.  
  940. @fb_r_edge_flush:
  941.  
  942. ; di = addr of upper left block to fill
  943. ; cx = # of bands to fill in (width)
  944.  
  945.     out_8   sc_data, all_planes ; write to all planes
  946.  
  947.     mov     dx, screen_width    ; dx = di increment
  948.     sub     dx, cx              ; = screen_width-# planes filled
  949.  
  950.     mov     ebx, ecx            ; bx = quick refill for cx
  951.     mov     si, [ebp].fb_ypos2  ; si = # of line to fill
  952.     mov     al, [ebp].fb_color  ; get fill color
  953.  
  954. @fb_middle_loop:
  955.     rep     stosb               ; fill in entire line
  956.  
  957.     mov     ecx, ebx            ; recharge cx (line width)
  958.     add     edi, edx            ; point to start of next line
  959.     loopx   si, @fb_middle_loop ; loop until all lines drawn
  960.  
  961.     jmp     s @fb_exit          ; outa here
  962.  
  963. @fb_one_band_only:
  964.     movzx   esi, ax                 ; get left clip mask, save x1
  965.     and     si, plane_bits          ; mask out row #
  966.     mov     al, left_clip_mask[esi] ; get left edge mask
  967.     mov     si, bx                  ; get right clip mask, save x2
  968.     and     si, plane_bits          ; mask out row #
  969.     and     al, right_clip_mask[esi] ; get right edge mask byte
  970.  
  971.     out_8   sc_data, al         ; clip for left & right masks
  972.  
  973.     mov     cx, [ebp].fb_ypos2  ; get # of lines to draw
  974.     mov     al, [ebp].fb_color  ; get fill color
  975.     clr     ebx                 ; wipe high word
  976.     mov     bx, screen_width    ; get vertical increment value
  977.  
  978. @fb_one_loop:
  979.     mov     [edi], al           ; fill in pixels
  980.     add     edi, ebx            ; point to next line (below)
  981.     loopjz  cx, @fb_exit        ; exit loop if all lines drawn
  982.  
  983.     mov     [edi], al           ; fill in pixels
  984.     add     edi, ebx            ; point to next line (below)
  985.     loopx   cx, @fb_one_loop    ; loop until left strip is drawn
  986.  
  987. @fb_exit:
  988.     pop     edi esi ebp         ; restore saved registers
  989.     ret     10                  ; exit and clean up stack
  990.  
  991.     endif
  992.     if x_draw_line eq 1
  993.  
  994. ;=====================================================
  995. ;draw_line (xpos1%, ypos1%, xpos2%, ypos2%, colornum%)
  996. ;=====================================================
  997. ;
  998. ; draws a line on the active display page
  999. ;
  1000. ; entry: xpos1    = x position of first point on line
  1001. ;        ypos1    = y position of first point on line
  1002. ;        xpos2    = x position of last point on line
  1003. ;        ypos2    = y position of last point on line
  1004. ;        colornum = color to draw line with
  1005. ;
  1006. ; exit:  no meaningful values returned
  1007. ;
  1008.  
  1009. dl_stack    struc
  1010.                 dd  ?x3 ; edi, esi, ebp
  1011.                 dd  ?   ; caller
  1012.     dl_colorf   db  ?,? ; line draw color
  1013.     dl_ypos2    dw  ?   ; y pos of last point
  1014.     dl_xpos2    dw  ?   ; x pos of last point
  1015.     dl_ypos1    dw  ?   ; y pos of first point
  1016.     dl_xpos1    dw  ?   ; x pos of first point
  1017. dl_stack    ends
  1018.  
  1019.         public draw_line
  1020.  
  1021. draw_line:
  1022.  
  1023.     push    ebp esi edi         ; preserve important registers
  1024.     mov     ebp, esp            ; set up stack frame
  1025.     cld                         ; direction flag = forward
  1026.  
  1027.     out_8   sc_index, map_mask  ; set up for plane select
  1028.     mov     ch, [ebp].dl_colorf ; save line color in ch
  1029.  
  1030. ; check line type
  1031.  
  1032.     movzx   esi, [ebp].dl_xpos1 ; ax = x1   is x1< x2?
  1033.     movzx   edi, [ebp].dl_xpos2 ; dx = x2
  1034.     cmp     si, di              ; is x1 < x2
  1035.     je      @dl_vline           ; if x1=x2, draw vertical line
  1036.     jl      @dl_noswap1         ; if x1 < x2, don't swap
  1037.  
  1038.     xchg    si, di              ; x2 is > x1, so swap them
  1039.  
  1040. @dl_noswap1:
  1041.  
  1042. ; si = x1, di = x2
  1043.  
  1044.     mov     ax, [ebp].dl_ypos1  ; ax = y1   is y1 <> y2?
  1045.     cmp     ax, [ebp].dl_ypos2  ; y1 = y2?
  1046.     je      @dl_horz            ; if so, draw a horizontal line
  1047.  
  1048.     jmp     @dl_brezham         ; diagonal line... go do it...
  1049.  
  1050. ; this code draws a horizontal line in mode x where:
  1051. ; si = x1, di = x2, and ax = y1/y2
  1052.  
  1053. @dl_horz:
  1054.  
  1055.     mul     screen_width        ; offset = ypos * screen_width
  1056.     mov     dx, ax              ; cx = line offset into page
  1057.  
  1058.     mov     ax, si                  ; get left edge, save x1
  1059.     and     si, plane_bits          ; mask out row #
  1060.     mov     bl, left_clip_mask[esi] ; get left edge mask
  1061.     mov     cx, di                  ; get right edge, save x2
  1062.     and     di, plane_bits          ; mask out row #
  1063.     mov     bh, right_clip_mask[edi] ; get right edge mask byte
  1064.  
  1065.     shr     ax, 2               ; get x1 byte # (=x1/4)
  1066.     shr     cx, 2               ; get x2 byte # (=x2/4)
  1067.  
  1068.     movzx   eax, ax             ; zero high words for add
  1069.     movzx   edx, dx
  1070.     movzx   ecx, cx
  1071.  
  1072.     mov     edi, current_page   ; point to active vga page
  1073.     add     edi, edx            ; point to start of line
  1074.     add     edi, eax            ; point to pixel x1
  1075.  
  1076.     sub     cx, ax              ; cx = # of bands (-1) to set
  1077.     jnz     @dl_longln          ; jump if longer than one segment
  1078.  
  1079.     and     bl, bh              ; otherwise, merge clip masks
  1080.  
  1081. @dl_longln:
  1082.  
  1083.     out_8   sc_data, bl         ; set the left clip mask
  1084.  
  1085.     mov     al, [ebp].dl_colorf ; get line color
  1086.     mov     bl, al              ; bl = copy of line color
  1087.     stosb                       ; set left (1-4) pixels
  1088.  
  1089.     jcxz    @dl_exit3           ; done if only one line segment
  1090.  
  1091.     dec     cx                  ; cx = # of middle segments
  1092.     jz      @dl_xrseg           ; if no middle segments....
  1093.  
  1094. ; draw middle segments
  1095.  
  1096.     out_8   dx, all_planes      ; write to all planes
  1097.  
  1098.     mov     al, bl              ; get color from bl
  1099.     rep     stosb               ; draw middle (4 pixel) segments
  1100.  
  1101. @dl_xrseg:
  1102.     out_8   dx, bh              ; select planes for right clip mask
  1103.     mov     al, bl              ; get color value
  1104.     stosb                       ; draw right (1-4) pixels
  1105. @dl_exit3:
  1106.     jmp     s @dl_exit          ; we are done...
  1107.  
  1108. ; this code draws a vertical line.  on entry:
  1109. ; ch = line color, si & di = x1
  1110.  
  1111. @dl_vline:
  1112.  
  1113.     mov     ax, [ebp].dl_ypos1  ; ax = y1
  1114.     mov     si, [ebp].dl_ypos2  ; si = y2
  1115.     cmp     ax, si              ; is y1 < y2?
  1116.     jle     @dl_noswap2         ; if so, don't swap them
  1117.  
  1118.     xchg    ax, si              ; ok, now y1 < y2
  1119.  
  1120. @dl_noswap2:
  1121.  
  1122.     sub     si, ax              ; si = line height (y2-y1+1)
  1123.     inc     si
  1124.  
  1125. ; ax = y1, di = x1, get offset into page into ax
  1126.  
  1127.     mul     screen_width        ; offset = y1 (ax) * screen width
  1128.     mov     dx, di              ; copy xpos into dx
  1129.     shr     di, 2               ; di = xpos/4
  1130.     add     ax, di              ; di = xpos/4 + screenwidth * y1
  1131.  
  1132.     movzx   eax, ax
  1133.     mov     edi, current_page   ; point to active vga page
  1134.     add     edi, eax            ; point to pixel x1, y1
  1135.  
  1136. ;select plane
  1137.  
  1138.     mov     cl, dl              ; cl = save x1
  1139.     and     cl, plane_bits      ; get x1 mod 4 (plane #)
  1140.     mov     ax, map_mask_plane1 ; code to set plane #1
  1141.     shl     ah, cl              ; change to correct plane #
  1142.     out_16  sc_index, ax        ; select plane
  1143.  
  1144.     mov     al, ch              ; get saved color
  1145.     mov     bx, screen_width    ; get offset to advance line by
  1146.     movzx   ebx, bx
  1147.  
  1148. @dl_vloop:
  1149.     mov     [edi], al           ; draw single pixel
  1150.     add     edi, ebx            ; point to next line
  1151.     loopjz  si, @dl_exit        ; lines--, exit if done
  1152.  
  1153.     mov     [edi], al           ; draw single pixel
  1154.     add     edi, ebx            ; point to next line
  1155.     loopx   si, @dl_vloop       ; lines--, loop until done
  1156.  
  1157. @dl_exit:
  1158.  
  1159.     jmp     @dl_exit2           ; done!
  1160.  
  1161. ; this code draws a diagonal line in mode x
  1162.  
  1163. @dl_brezham:
  1164.     mov     edi, current_page   ; point to active vga page
  1165.  
  1166.     mov     ax, [ebp].dl_ypos1  ; get y1 value
  1167.     mov     bx, [ebp].dl_ypos2  ; get y2 value
  1168.     mov     cx, [ebp].dl_xpos1  ; get starting xpos
  1169.  
  1170.     cmp     bx, ax              ; y2-y1 is?
  1171.     jnc     @dl_deltayok        ; if y2>=y1 then goto...
  1172.  
  1173.     xchg    bx, ax              ; swap em...
  1174.     mov     cx, [ebp].dl_xpos2  ; get new starting xpos
  1175.  
  1176. @dl_deltayok:
  1177.     mul     screen_width        ; offset = screen_width * y1
  1178.     movzx   eax, ax
  1179.  
  1180.     add     edi, eax            ; di -> start of line y1 on page
  1181.     mov     ax, cx              ; ax = xpos (x1)
  1182.     shr     ax, 2               ; /4 = byte offset into line
  1183.     add     edi, eax            ; di = starting pos (x1,y1)
  1184.  
  1185.     mov     al, 11h             ; staring mask
  1186.     and     cl, plane_bits      ; get plane #
  1187.     shl     al, cl              ; and shift into place
  1188.     mov     ah, [ebp].dl_colorf ; color in hi bytes
  1189.  
  1190.     push    ax                  ; save mask,color...
  1191.  
  1192.     mov     ah, al              ; plane # in ah
  1193.     mov     al, map_mask        ; select plane register
  1194.     out_16  sc_index, ax        ; select initial plane
  1195.  
  1196.     mov     ax, [ebp].dl_xpos1  ; get x1 value
  1197.     mov     bx, [ebp].dl_ypos1  ; get y1 value
  1198.     mov     cx, [ebp].dl_xpos2  ; get x2 value
  1199.     mov     dx, [ebp].dl_ypos2  ; get y2 value
  1200.  
  1201.     movzx   ebp, screen_width   ; use bp for line width to
  1202.                                 ; to avoid extra memory access
  1203.  
  1204.     sub     dx, bx              ; figure delta_y
  1205.     jnc     @dl_deltayok2       ; jump if y2 >= y1
  1206.  
  1207.     add     bx, dx              ; put y2 into y1
  1208.     neg     dx                  ; abs(delta_y)
  1209.     xchg    ax, cx              ; and exchange x1 and x2
  1210.  
  1211. @dl_deltayok2:
  1212.     mov     bx, 08000h          ; seed for fraction accumulator
  1213.  
  1214.     sub     cx, ax              ; figure delta_x
  1215.     jc      @dl_drawleft        ; if negative, go left
  1216.  
  1217.     jmp     @dl_drawright       ; draw line that slopes right
  1218.  
  1219. @dl_drawleft:
  1220.  
  1221.     neg     cx                  ; abs(delta_x)
  1222.  
  1223.     cmp     cx, dx              ; is delta_x < delta_y?
  1224.     jb      @dl_steepleft       ; yes, so go do steep line
  1225.                                 ; (delta_y iterations)
  1226.  
  1227. ; draw a shallow line to the left in mode x
  1228.  
  1229. @dl_shallowleft:
  1230.     clr     ax                  ; zero low word of delta_y * 10000h
  1231.     sub     ax, dx              ; dx:ax <- dx * 0ffffh
  1232.     sbb     dx, 0               ; include carry
  1233.     div     cx                  ; divide by delta_x
  1234.  
  1235.     mov     si, bx              ; si = accumulator
  1236.     mov     bx, ax              ; bx = add fraction
  1237.     pop     ax                  ; get color, bit mask
  1238.     mov     dx, sc_data         ; sequence controller data register
  1239.     inc     cx                  ; inc delta_x so we can unroll loop
  1240.  
  1241. ; loop (x2) to draw pixels, move left, and maybe down...
  1242.  
  1243. @dl_sllloop:
  1244.     mov     [edi], ah           ; set first pixel, plane data set up
  1245.     loopjz  cx, @dl_sllexit     ; delta_x--, exit if done
  1246.  
  1247.     add     si, bx              ; add numerator to accumulator
  1248.     jnc     @dl_slll2nc         ; move down on carry
  1249.  
  1250.     add     edi, ebp            ; move down one line...
  1251.  
  1252. @dl_slll2nc:
  1253.     dec     edi                 ; left one addr
  1254.     ror     al, 1               ; move left one plane, back on 0 1 2
  1255.     cmp     al, 87h             ; wrap?, if al <88 then carry set
  1256.     adc     edi, 0              ; adjust address: di = di + carry
  1257.     out     dx, al              ; set up new bit plane mask
  1258.  
  1259.     mov     [edi], ah           ; set pixel
  1260.     loopjz  cx, @dl_sllexit     ; delta_x--, exit if done
  1261.  
  1262.     add     si, bx              ; add numerator to accumulator,
  1263.     jnc     @dl_slll3nc         ; move down on carry
  1264.  
  1265.     add     edi, ebp            ; move down one line...
  1266.  
  1267. @dl_slll3nc:                    ; now move left a pixel...
  1268.     dec     edi                 ; left one addr
  1269.     ror     al, 1               ; move left one plane, back on 0 1 2
  1270.     cmp     al, 87h             ; wrap?, if al <88 then carry set
  1271.     adc     edi, 0              ; adjust address: di = di + carry
  1272.     out     dx, al              ; set up new bit plane mask
  1273.     jmp     s @dl_sllloop       ; loop until done
  1274.  
  1275. @dl_sllexit:
  1276.     jmp     @dl_exit2           ; and exit
  1277.  
  1278. ; draw a steep line to the left in mode x
  1279.  
  1280. @dl_steepleft:
  1281.     clr     ax                  ; zero low word of delta_y * 10000h
  1282.     xchg    dx, cx              ; delta_y switched with delta_x
  1283.     div     cx                  ; divide by delta_y
  1284.  
  1285.     mov     si, bx              ; si = accumulator
  1286.     mov     bx, ax              ; bx = add fraction
  1287.     pop     ax                  ; get color, bit mask
  1288.     mov     dx, sc_data         ; sequence controller data register
  1289.     inc     cx                  ; inc delta_y so we can unroll loop
  1290.  
  1291. ; loop (x2) to draw pixels, move down, and maybe left
  1292.  
  1293. @dl_stlloop:
  1294.  
  1295.     mov     [edi], ah           ; set first pixel
  1296.     loopjz  cx, @dl_stlexit     ; delta_y--, exit if done
  1297.  
  1298.     add     si, bx              ; add numerator to accumulator
  1299.     jnc     @dl_stlnc2          ; no carry, just move down!
  1300.  
  1301.     dec     edi                 ; move left one addr
  1302.     ror     al, 1               ; move left one plane, back on 0 1 2
  1303.     cmp     al, 87h             ; wrap?, if al <88 then carry set
  1304.     adc     edi, 0              ; adjust address: di = di + carry
  1305.     out     dx, al              ; set up new bit plane mask
  1306.  
  1307. @dl_stlnc2:
  1308.     add     edi, ebp            ; advance to next line.
  1309.  
  1310.     mov     [edi], ah           ; set pixel
  1311.     loopjz  cx, @dl_stlexit     ; delta_y--, exit if done
  1312.  
  1313.     add     si, bx              ; add numerator to accumulator
  1314.     jnc     @dl_stlnc3          ; no carry, just move down!
  1315.  
  1316.     dec     edi                 ; move left one addr
  1317.     ror     al, 1               ; move left one plane, back on 0 1 2
  1318.     cmp     al, 87h             ; wrap?, if al <88 then carry set
  1319.     adc     edi, 0              ; adjust address: di = di + carry
  1320.     out     dx, al              ; set up new bit plane mask
  1321.  
  1322. @dl_stlnc3:
  1323.     add     edi, ebp            ; advance to next line.
  1324.     jmp     s @dl_stlloop       ; loop until done
  1325.  
  1326. @dl_stlexit:
  1327.     jmp     @dl_exit2           ; and exit
  1328.  
  1329. ; draw a line that goes to the right...
  1330.  
  1331. @dl_drawright:
  1332.     cmp     cx, dx              ; is delta_x < delta_y?
  1333.     jb      @dl_steepright      ; yes, so go do steep line
  1334.                                 ; (delta_y iterations)
  1335.  
  1336. ; draw a shallow line to the right in mode x
  1337.  
  1338. @dl_shallowright:
  1339.     clr     ax                  ; zero low word of delta_y * 10000h
  1340.     sub     ax, dx              ; dx:ax <- dx * 0ffffh
  1341.     sbb     dx, 0               ; include carry
  1342.     div     cx                  ; divide by delta_x
  1343.  
  1344.     mov     si, bx              ; si = accumulator
  1345.     mov     bx, ax              ; bx = add fraction
  1346.     pop     ax                  ; get color, bit mask
  1347.     mov     dx, sc_data         ; sequence controller data register
  1348.     inc     cx                  ; inc delta_x so we can unroll loop
  1349.  
  1350. ; loop (x2) to draw pixels, move right, and maybe down...
  1351.  
  1352. @dl_slrloop:
  1353.     mov     [edi], ah           ; set first pixel, mask is set up
  1354.     loopjz  cx, @dl_slrexit     ; delta_x--, exit if done..
  1355.  
  1356.     add     si, bx              ; add numerator to accumulator
  1357.     jnc     @dl_slr2nc          ; don't move down if carry not set
  1358.  
  1359.     add     edi, ebp            ; move down one line...
  1360.  
  1361. @dl_slr2nc:                     ; now move right a pixel...
  1362.     rol     al, 1               ; move right one addr if plane = 0
  1363.     cmp     al, 12h             ; wrap? if al >12 then carry not set
  1364.     adc     edi, 0              ; adjust address: di = di + carry
  1365.     out     dx, al              ; set up new bit plane mask
  1366.  
  1367.     mov     [edi], ah           ; set pixel
  1368.     loopjz  cx, @dl_slrexit     ; delta_x--, exit if done..
  1369.  
  1370.     add     si, bx              ; add numerator to accumulator
  1371.     jnc     @dl_slr3nc          ; don't move down if carry not set
  1372.  
  1373.     add     edi, ebp            ; move down one line...
  1374.  
  1375. @dl_slr3nc:
  1376.     rol     al, 1               ; move right one addr if plane = 0
  1377.     cmp     al, 12h             ; wrap? if al >12 then carry not set
  1378.     adc     edi, 0              ; adjust address: di = di + carry
  1379.     out     dx, al              ; set up new bit plane mask
  1380.     jmp     s @dl_slrloop       ; loop till done
  1381.  
  1382. @dl_slrexit:
  1383.     jmp     @dl_exit2           ; and exit
  1384.  
  1385. ; draw a steep line to the right in mode x
  1386.  
  1387. @dl_steepright:
  1388.     clr     ax                  ; zero low word of delta_y * 10000h
  1389.     xchg    dx, cx              ; delta_y switched with delta_x
  1390.     div     cx                  ; divide by delta_y
  1391.  
  1392.     mov     si, bx              ; si = accumulator
  1393.     mov     bx, ax              ; bx = add fraction
  1394.     pop     ax                  ; get color, bit mask
  1395.     mov     dx, sc_data         ; sequence controller data register
  1396.     inc     cx                  ; inc delta_y so we can unroll loop
  1397.  
  1398. ; loop (x2) to draw pixels, move down, and maybe right
  1399.  
  1400. @strloop:
  1401.     mov     [edi], ah           ; set first pixel, mask is set up
  1402.     loopjz  cx, @dl_exit2       ; delta_y--, exit if done
  1403.  
  1404.     add     si, bx              ; add numerator to accumulator
  1405.     jnc     @strnc2             ; if no carry then just go down...
  1406.  
  1407.     rol     al, 1               ; move right one addr if plane = 0
  1408.     cmp     al, 12h             ; wrap? if al >12 then carry not set
  1409.     adc     edi, 0              ; adjust address: di = di + carry
  1410.     out     dx, al              ; set up new bit plane mask
  1411.  
  1412. @strnc2:
  1413.     add     edi, ebp            ; advance to next line.
  1414.  
  1415.     mov     [edi], ah           ; set pixel
  1416.     loopjz  cx, @dl_exit2       ; delta_y--, exit if done
  1417.  
  1418.     add     si, bx              ; add numerator to accumulator
  1419.     jnc     @strnc3             ; if no carry then just go down...
  1420.  
  1421.     rol     al, 1               ; move right one addr if plane = 0
  1422.     cmp     al, 12h             ; wrap? if al >12 then carry not set
  1423.     adc     edi, 0              ; adjust address: di = di + carry
  1424.     out     dx, al              ; set up new bit plane mask
  1425.  
  1426. @strnc3:
  1427.     add     edi, ebp            ; advance to next line.
  1428.     jmp     s @strloop          ; loop till done
  1429.  
  1430. @dl_exit2:
  1431.     pop     edi esi ebp         ; restore saved registers
  1432.     ret     10                  ; exit and clean up stack
  1433.  
  1434.     endif
  1435.  
  1436. ; ===== dac color register routines =====
  1437.  
  1438. ;=================================================
  1439. ;set_dac_register (register%, red%, green%, blue%)
  1440. ;=================================================
  1441. ;
  1442. ; sets a single (rgb) vga palette register
  1443. ;
  1444. ; entry: register = the dac # to modify (0-255)
  1445. ;        red      = the new red intensity (0-63)
  1446. ;        green    = the new green intensity (0-63)
  1447. ;        blue     = the new blue intensity (0-63)
  1448. ;
  1449. ; exit:  no meaningful values returned
  1450. ;
  1451.  
  1452. sdr_stack   struc
  1453.                     dd  ?   ; ebp
  1454.                     dd  ?   ; caller
  1455.     sdr_blue        db  ?,? ; blue data value
  1456.     sdr_green       db  ?,? ; green data value
  1457.     sdr_red         db  ?,? ; red data value
  1458.     sdr_register    db  ?,? ; palette register #
  1459. sdr_stack   ends
  1460.  
  1461.     public  set_dac_register
  1462.  
  1463. set_dac_register:
  1464.  
  1465.     push    ebp                 ; save bp
  1466.     mov     ebp, esp            ; set up stack frame
  1467.  
  1468. ; select which dac register to modify
  1469.  
  1470.     out_8   dac_write_addr, [ebp].sdr_register
  1471.  
  1472.     mov     dx, pel_data_reg    ; dac data register
  1473.     out_8   dx, [ebp].sdr_red   ; set red intensity
  1474.     out_8   dx, [ebp].sdr_green ; set green intensity
  1475.     out_8   dx, [ebp].sdr_blue  ; set blue intensity
  1476.  
  1477.     pop     ebp                 ; restore registers
  1478.     ret     8                   ; exit & clean up stack
  1479.  
  1480. ;====================================================
  1481. ;get_dac_register (register%, &red%, &green%, &blue%)
  1482. ;====================================================
  1483. ;
  1484. ; reads the rgb values of a single vga palette register
  1485. ;
  1486. ; entry: register = the dac # to read (0-255)
  1487. ;        red      = offset to red variable in ds
  1488. ;        green    = offset to green variable in ds
  1489. ;        blue     = offset to blue variable in ds
  1490. ;
  1491. ; exit:  the values of the integer variables red,
  1492. ;        green, and blue are set to the values
  1493. ;        taken from the specified dac register.
  1494. ;
  1495.  
  1496. gdr_stack   struc
  1497.                     dd  ?   ; ebp
  1498.                     dd  ?   ; caller
  1499.     gdr_blue        dd  ?   ; addr of blue data value (where to put)
  1500.     gdr_green       dd  ?   ; addr of green data value
  1501.     gdr_red         dd  ?   ; addr of red data value
  1502.     gdr_register    db  ?,? ; palette register #
  1503. gdr_stack   ends
  1504.  
  1505.     public  get_dac_register
  1506.  
  1507. get_dac_register:
  1508.  
  1509.     push    ebp                 ; save bp
  1510.     mov     ebp, esp            ; set up stack frame
  1511.  
  1512. ; select which dac register to read in
  1513.  
  1514.     out_8   dac_read_addr, [ebp].gdr_register
  1515.  
  1516.     mov     dx, pel_data_reg    ; dac data register
  1517.     clr     ax                  ; clear ax
  1518.  
  1519.     in      al, dx              ; read red value
  1520.     mov     ebx, [ebp].gdr_red  ; get address of red%
  1521.     mov     [ebx], ax           ; *red% = ax
  1522.  
  1523.     in      al, dx              ; read green value
  1524.     mov     ebx, [ebp].gdr_green; get address of green%
  1525.     mov     [ebx], ax           ; *green% = ax
  1526.  
  1527.     in      al, dx              ; read blue value
  1528.     mov     ebx, [ebp].gdr_blue ; get address of blue%
  1529.     mov     [ebx], ax           ; *blue% = ax
  1530.  
  1531.     pop     ebp                 ; restore registers
  1532.     ret     14                  ; exit & clean up stack
  1533.  
  1534. ;===========================================================
  1535. ;load_dac_registers (seg paldata, startreg%, endreg%, sync%)
  1536. ;===========================================================
  1537. ;
  1538. ; sets a block of vga palette registers
  1539. ;
  1540. ; entry: paldata  = far pointer to block of palette data
  1541. ;        startreg = first register # in range to set (0-255)
  1542. ;        endreg   = last register # in range to set (0-255)
  1543. ;        sync     = wait for vertical retrace flag (boolean)
  1544. ;
  1545. ; exit:  no meaningful values returned
  1546. ;
  1547. ; notes: paldata is a lifar array of 3 byte palette values
  1548. ;        in the order: red  (0-63), green (0-63), blue (0-63)
  1549. ;
  1550.  
  1551. ldr_stack   struc
  1552.                     dd  ?,? ; ebp, esi
  1553.                     dd  ?   ; caller
  1554.     ldr_sync        dw  ?   ; vertical sync flag
  1555.     ldr_endreg      db  ?,? ; last register #
  1556.     ldr_startreg    db  ?,? ; first register #
  1557.     ldr_paldata     dd  ?   ; far ptr to palette data
  1558. ldr_stack   ends
  1559.  
  1560.     public  load_dac_registers
  1561.  
  1562. load_dac_registers:
  1563.  
  1564.     push    ebp esi             ; save registers
  1565.     mov     ebp, esp            ; set up stack frame
  1566.  
  1567.     mov     ax, [ebp].ldr_sync  ; get vertical sync flag
  1568.     or      ax, ax              ; is sync flag = 0?
  1569.     jz      @ldr_load           ; if so, skip call
  1570.  
  1571.     call    sync_display        ; wait for vsync
  1572.  
  1573. ; determine register #'s, size to copy, etc
  1574.  
  1575. @ldr_load:
  1576.  
  1577.     mov     esi, [ebp].ldr_paldata  ; esi -> palette data
  1578.     mov     dx, dac_write_addr      ; dac register # selector
  1579.  
  1580.     clr     ax, bx                  ; clear for byte loads
  1581.     mov     al, [ebp].ldr_startreg  ; get start register
  1582.     mov     bl, [ebp].ldr_endreg    ; get end register
  1583.  
  1584.     sub     bx, ax              ; bx = # of dac registers -1
  1585.     inc     bx                  ; bx = # of dac registers
  1586.     mov     cx, bx              ; cx = # of dac registers
  1587.     add     cx, bx              ; cx =  "   " * 2
  1588.     add     cx, bx              ; cx =  "   " * 3
  1589.     cld                         ; block outs forward
  1590.     out     dx, al              ; set up correct register #
  1591.  
  1592. ; load a block of dac registers
  1593.  
  1594.     mov     dx, pel_data_reg    ; dac data register
  1595.     movzx   ecx,cx
  1596.  
  1597.     rep     outsb               ; block set dac registers
  1598.  
  1599.     pop     esi ebp             ; restore registers
  1600.     ret     10                  ; exit & clean up stack
  1601.  
  1602. ;====================================================
  1603. ;read_dac_registers (seg paldata, startreg%, endreg%)
  1604. ;====================================================
  1605. ;
  1606. ; reads a block of vga palette registers
  1607. ;
  1608. ; entry: paldata  = far pointer to block to store palette data
  1609. ;        startreg = first register # in range to read (0-255)
  1610. ;        endreg   = last register # in range to read (0-255)
  1611. ;
  1612. ; exit:  no meaningful values returned
  1613. ;
  1614. ; notes: paldata is a lifar array of 3 byte palette values
  1615. ;        in the order: red  (0-63), green (0-63), blue (0-63)
  1616. ;
  1617.  
  1618. rdr_stack   struc
  1619.                     dd  ?,? ; ebp, edi
  1620.                     dd  ?   ; caller
  1621.     rdr_endreg      db  ?,? ; last register #
  1622.     rdr_startreg    db  ?,? ; first register #
  1623.     rdr_paldata     dd  ?   ; far ptr to palette data
  1624. rdr_stack   ends
  1625.  
  1626.     public  read_dac_registers
  1627.  
  1628. read_dac_registers:
  1629.  
  1630.     push    ebp edi             ; save registers
  1631.     mov     ebp, esp            ; set up stack frame
  1632.  
  1633. ; determine register #'s, size to copy, etc
  1634.  
  1635.     mov     edi, [ebp].rdr_paldata  ; edi -> palette buffer
  1636.     mov     dx, dac_read_addr       ; dac register # selector
  1637.  
  1638.     clr     ax, bx                  ; clear for byte loads
  1639.     mov     al, [ebp].rdr_startreg  ; get start register
  1640.     mov     bl, [ebp].rdr_endreg    ; get end register
  1641.  
  1642.     sub     bx, ax              ; bx = # of dac registers -1
  1643.     inc     bx                  ; bx = # of dac registers
  1644.     mov     cx, bx              ; cx = # of dac registers
  1645.     add     cx, bx              ; cx =  "   " * 2
  1646.     add     cx, bx              ; cx =  "   " * 3
  1647.     cld                         ; block ins forward
  1648.  
  1649. ; read a block of dac registers
  1650.  
  1651.     out     dx, al              ; set up correct register #
  1652.     mov     dx, pel_data_reg    ; dac data register
  1653.     movzx   ecx,cx
  1654.  
  1655.     rep     insb                ; block read dac registers
  1656.  
  1657.     pop     edi ebp             ; restore registers
  1658.     ret     8                   ; exit & clean up stack
  1659.  
  1660. ; ===== page flipping and scrolling routines =====
  1661.  
  1662. ;=========================
  1663. ;set_active_page (pageno%)
  1664. ;=========================
  1665. ;
  1666. ; sets the active display page to be used for future drawing
  1667. ;
  1668. ; entry: pageno = display page to make active
  1669. ;        (values: 0 to number of pages - 1)
  1670. ;
  1671. ; exit:  no meaningful values returned
  1672. ;
  1673.  
  1674. sap_stack   struc
  1675.                 dd  ?   ; ebp
  1676.                 dd  ?   ; caller
  1677.     sap_page    dw  ?   ; page # for drawing
  1678. sap_stack   ends
  1679.  
  1680.     public  set_active_page
  1681.  
  1682. set_active_page:
  1683.  
  1684.     push    ebp                 ; preserve registers
  1685.     mov     ebp, esp            ; set up stack frame
  1686.  
  1687.     movzx   ebx, [ebp].sap_page ; get desired page #
  1688.     cmp     bx, last_page       ; is page # valid?
  1689.     jae     @sap_exit           ; if not, do nothing
  1690.  
  1691.     mov     active_page, bx     ; set active page #
  1692.  
  1693.     shl     bx, 2               ; scale page # to dword
  1694.     mov     eax, page_addr[ebx] ; get offset to page
  1695.  
  1696.     mov     current_page, eax   ; and set for future mov's
  1697.  
  1698. @sap_exit:
  1699.     pop     ebp                 ; restore registers
  1700.     ret     2                   ; exit and clean up stack
  1701.  
  1702. ;================
  1703. ;get_active_page%
  1704. ;================
  1705. ;
  1706. ; returns the video page # currently used for drawing
  1707. ;
  1708. ; entry: no parameters are passed
  1709. ;
  1710. ; exit:  ax = current video page used for drawing
  1711. ;
  1712.  
  1713.     public  get_active_page
  1714.  
  1715. get_active_page:
  1716.  
  1717.     mov     ax, active_page     ; get active page #
  1718.     ret                         ; exit and clean up stack
  1719.  
  1720. ;===============================
  1721. ;set_display_page (displaypage%)
  1722. ;===============================
  1723. ;
  1724. ; sets the currently visible display page.
  1725. ; when called this routine syncronizes the display
  1726. ; to the vertical blank.
  1727. ;
  1728. ; entry: pageno = display page to show on the screen
  1729. ;        (values: 0 to number of pages - 1)
  1730. ;
  1731. ; exit:  no meaningful values returned
  1732. ;
  1733.  
  1734. sdp_stack   struc
  1735.                 dd  ?       ; ebp
  1736.                 dd  ?       ; caller
  1737.     sdp_page    dw  ?       ; page # to display...
  1738. sdp_stack   ends
  1739.  
  1740.     public  set_display_page
  1741.  
  1742. set_display_page:
  1743.  
  1744.     push    ebp                 ; preserve registers
  1745.     mov     ebp, esp            ; set up stack frame
  1746.  
  1747.     movzx   ebx, [ebp].sdp_page ; get desired page #
  1748.     cmp     bx, last_page       ; is page # valid?
  1749.     jae     @sdp_exit           ; if not, do nothing
  1750.  
  1751.     mov     display_page, bx    ; set display page #
  1752.  
  1753.     shl     bx, 2               ; scale page # to dword
  1754.     mov     ecx, page_addr[ebx] ; get offset in memory to page
  1755.     add     ecx, current_moffset ; adjust for any scrolling
  1756.     add     ecx,_code32a        ; adjust for protected mode
  1757.  
  1758. ; wait if we are currently in a vertical retrace
  1759.  
  1760.     mov     dx, input_1         ; input status #1 register
  1761.  
  1762. @dp_wait0:
  1763.     in      al, dx              ; get vga status
  1764.     and     al, vert_retrace    ; in display mode yet?
  1765.     jnz     @dp_wait0           ; if not, wait for it
  1766.  
  1767. ; set the start display address to the new page
  1768.  
  1769.     mov     dx, crtc_index      ; we change the vga sequencer
  1770.  
  1771.     mov     al, start_disp_lo   ; display start low register
  1772.     mov     ah, cl              ; low 8 bits of start addr
  1773.     out     dx, ax              ; set display addr low
  1774.  
  1775.     mov     al, start_disp_hi   ; display start high register
  1776.     mov     ah, ch              ; high 8 bits of start addr
  1777.     out     dx, ax              ; set display addr high
  1778.  
  1779. ; wait for a vertical retrace to smooth out things
  1780.  
  1781.     mov     dx, input_1         ; input status #1 register
  1782.  
  1783. @dp_wait1:
  1784.     in      al, dx              ; get vga status
  1785.     and     al, vert_retrace    ; vertical retrace start?
  1786.     jz      @dp_wait1           ; if not, wait for it
  1787.  
  1788. @sdp_exit:
  1789.     pop     ebp                 ; restore registers
  1790.     ret     2                   ; exit and clean up stack
  1791.  
  1792. ;=================
  1793. ;get_display_page%
  1794. ;=================
  1795. ;
  1796. ; returns the video page # currently displayed
  1797. ;
  1798. ; entry: no parameters are passed
  1799. ;
  1800. ; exit:  ax = current video page being displayed
  1801. ;
  1802.  
  1803.     public  get_display_page
  1804.  
  1805. get_display_page:
  1806.  
  1807.     mov     ax, display_page    ; get display page #
  1808.     ret                         ; exit & clean up stack
  1809.  
  1810.     if x_set_window eq 1
  1811.  
  1812. ;=======================================
  1813. ;set_window (displaypage%, xpos%, ypos%)
  1814. ;=======================================
  1815. ;
  1816. ; since a logical screen can be larger than the physical
  1817. ; screen, scrolling is possible.  this routine sets the
  1818. ; upper left corner of the screen to the specified pixel.
  1819. ; also sets the display page to simplify combined page
  1820. ; flipping and scrolling.  when called this routine
  1821. ; syncronizes the display to the vertical blank.
  1822. ;
  1823. ; entry: displaypage = display page to show on the screen
  1824. ;        xpos        = # of pixels to shift screen right
  1825. ;        ypos        = # of lines to shift screen down
  1826. ;
  1827. ; exit:  no meaningful values returned
  1828. ;
  1829.  
  1830. sw_stack    struc
  1831.                 dd  ?   ; ebp
  1832.                 dd  ?   ; caller
  1833.     sw_ypos     dw  ?   ; y pos of ul screen corner
  1834.     sw_xpos     dw  ?   ; x pos of ul screen corner
  1835.     sw_page     dw  ?   ; (new) display page
  1836. sw_stack    ends
  1837.  
  1838.         public set_window
  1839.  
  1840. set_window:
  1841.  
  1842.     push    ebp                 ; preserve registers
  1843.     mov     ebp, esp            ; set up stack frame
  1844.  
  1845. ; check if our scroll offsets are valid
  1846.  
  1847.     mov     bx, [ebp].sw_page   ; get desired page #
  1848.     cmp     bx, last_page       ; is page # valid?
  1849.     jae     @sw_exit            ; if not, do nothing
  1850.  
  1851.     mov     ax, [ebp].sw_ypos   ; get desired y offset
  1852.     cmp     ax, max_yoffset     ; is it within limits?
  1853.     ja      @sw_exit            ; if not, exit
  1854.  
  1855.     mov     cx, [ebp].sw_xpos   ; get desired x offset
  1856.     cmp     cx, max_xoffset     ; is it within limits?
  1857.     ja      @sw_exit            ; if not, exit
  1858.  
  1859. ; compute proper display start address to use
  1860.  
  1861.     mul     screen_width        ; ax = yoffset * line width
  1862.     shr     cx, 2               ; cx / 4 = bytes into line
  1863.     add     ax, cx              ; ax = offset of upper left pixel
  1864.     movzx   eax, ax
  1865.     movzx   ebx, bx
  1866.  
  1867.     mov     current_moffset, eax ; save offset info
  1868.  
  1869.     mov     display_page, bx    ; set current page #
  1870.     shl     bx, 2               ; scale page # to dword
  1871.     add     eax, page_addr[ebx] ; get offset in vga to page
  1872.     add     eax,_code32a        ; adjust for protected mode segment
  1873.     mov     bx, ax              ; bx = desired display start
  1874.  
  1875.     mov     dx, input_1         ; input status #1 register
  1876.  
  1877. ; wait if we are currently in a vertical retrace
  1878.  
  1879. @sw_wait0:
  1880.     in      al, dx              ; get vga status
  1881.     and     al, vert_retrace    ; in display mode yet?
  1882.     jnz     @sw_wait0           ; if not, wait for it
  1883.  
  1884. ; set the start display address to the new window
  1885.  
  1886.     mov     dx, crtc_index      ; we change the vga sequencer
  1887.     mov     al, start_disp_lo   ; display start low register
  1888.     mov     ah, bl              ; low 8 bits of start addr
  1889.     out     dx, ax              ; set display addr low
  1890.  
  1891.     mov     al, start_disp_hi   ; display start high register
  1892.     mov     ah, bh              ; high 8 bits of start addr
  1893.     out     dx, ax              ; set display addr high
  1894.  
  1895. ; wait for a vertical retrace to smooth out things
  1896.  
  1897.     mov     dx, input_1         ; input status #1 register
  1898.  
  1899. @sw_wait1:
  1900.     in      al, dx              ; get vga status
  1901.     and     al, vert_retrace    ; vertical retrace start?
  1902.     jz      @sw_wait1           ; if not, wait for it
  1903.  
  1904. ; now set the horizontal pixel pan values
  1905.  
  1906.     out_8   attrib_ctrl, pixel_pan_reg  ; select pixel pan register
  1907.  
  1908.     mov     ax, [ebp].sw_xpos   ; get desired x offset
  1909.     and     al, 03              ; get # of pixels to pan (0-3)
  1910.     shl     al, 1               ; shift for 256 color mode
  1911.     out     dx, al              ; fine tune the display!
  1912.  
  1913. @sw_exit:
  1914.     pop     ebp                 ; restore saved registers
  1915.     ret     6                   ; exit and clean up stack
  1916.  
  1917. ;=============
  1918. ;get_x_offset%
  1919. ;=============
  1920. ;
  1921. ; returns the x coordinate of the pixel currently display
  1922. ; in the upper left corner of the display
  1923. ;
  1924. ; entry: no parameters are passed
  1925. ;
  1926. ; exit:  ax = current horizontal scroll offset
  1927. ;
  1928.  
  1929.     public  get_x_offset
  1930.  
  1931. get_x_offset:
  1932.  
  1933.     mov     ax, current_xoffset ; get current horz offset
  1934.     ret                         ; exit & clean up stack
  1935.  
  1936. ;=============
  1937. ;get_y_offset%
  1938. ;=============
  1939. ;
  1940. ; returns the y coordinate of the pixel currently display
  1941. ; in the upper left corner of the display
  1942. ;
  1943. ; entry: no parameters are passed
  1944. ;
  1945. ; exit:  ax = current vertical scroll offset
  1946. ;
  1947.  
  1948.     public  get_y_offset
  1949.  
  1950. get_y_offset:
  1951.  
  1952.     mov     ax, current_yoffset ; get current vertical offset
  1953.     ret                         ; exit & clean up stack
  1954.  
  1955.     endif
  1956.  
  1957. ;============
  1958. ;sync_display
  1959. ;============
  1960. ;
  1961. ; pauses the computer until the next vertical retrace starts
  1962. ;
  1963. ; entry: no parameters are passed
  1964. ;
  1965. ; exit:  no meaningful values returned
  1966. ;
  1967.  
  1968.     public  sync_display
  1969.  
  1970. sync_display:
  1971.  
  1972.     mov     dx, input_1         ; input status #1 register
  1973.  
  1974. ; wait for any current retrace to end
  1975.  
  1976. @sd_wait0:
  1977.     in      al, dx              ; get vga status
  1978.     and     al, vert_retrace    ; in display mode yet?
  1979.     jnz     @sd_wait0           ; if not, wait for it
  1980.  
  1981. ; wait for the start of the next vertical retrace
  1982.  
  1983. @sd_wait1:
  1984.     in      al, dx              ; get vga status
  1985.     and     al, vert_retrace    ; vertical retrace start?
  1986.     jz      @sd_wait1           ; if not, wait for it
  1987.  
  1988.     ret
  1989.  
  1990. ; ===== text display routines =====
  1991.  
  1992.     if x_gprintc eq 1
  1993.  
  1994. ;==================================================
  1995. ;gprintc (charnum%, xpos%, ypos%, colorf%, colorb%)
  1996. ;==================================================
  1997. ;
  1998. ; draws an ascii text character using the currently selected
  1999. ; 8x8 font on the active display page.  it would be a simple
  2000. ; exercise to make this routine process variable height fonts.
  2001. ;
  2002. ; entry: charnum = ascii character # to draw
  2003. ;        xpos    = x position to draw character at
  2004. ;        ypos    = y position of to draw character at
  2005. ;        colorf  = color to draw text character in
  2006. ;        colorb  = color to set background to
  2007. ;
  2008. ; exit:  no meaningful values returned
  2009. ;
  2010.  
  2011. gpc_stack   struc
  2012.     gpc_width   dd  ?   ; screen width-1
  2013.     gpc_lines   db  ?,? ; scan lines to decode
  2014.     gpc_t_sets  dd  ?   ; saved charset segment
  2015.                 dd  ?x3 ; edi, esi, ebp
  2016.                 dd  ?   ; caller
  2017.     gpc_colorb  db  ?,? ; background color
  2018.     gpc_colorf  db  ?,? ; text color
  2019.     gpc_ypos    dw  ?   ; y position to print at
  2020.     gpc_xpos    dw  ?   ; x position to print at
  2021.     gpc_char    db  ?,? ; character to print
  2022. gpc_stack   ends
  2023.  
  2024.         public gprintc
  2025.  
  2026. gprintc:
  2027.  
  2028.     push    ebp esi edi         ; preserve important registers
  2029.     sub     esp, 10             ; allocate workspace on stack
  2030.     mov     ebp, esp            ; set up stack frame
  2031.  
  2032.     mov     edi, current_page   ; point to active vga page
  2033.  
  2034.     movzx   eax, screen_width   ; get logical line width
  2035.     mov     ebx, eax            ; bx = screen width
  2036.     dec     bx                  ;    = screen width-1
  2037.     mov     [ebp].gpc_width,ebx ; save for later use
  2038.  
  2039.     mul     [ebp].gpc_ypos      ; start of line = ypos * width
  2040.     add     edi, eax            ; di -> start of line ypos
  2041.  
  2042.     movzx   eax, [ebp].gpc_xpos ; get xpos of character
  2043.     mov     cx, ax              ; save copy of xpos
  2044.     shr     ax, 2               ; bytes into line = xpos/4
  2045.     add     edi, eax            ; di -> (xpos, ypos)
  2046.  
  2047. ;get source addr of character bit map  & save
  2048.  
  2049.     mov     al, [ebp].gpc_char  ; get character #
  2050.     test    al, 080h            ; is hi bit set?
  2051.     jz      @gpc_lowchar        ; nope, use low char set ptr
  2052.  
  2053.     mov     ebx, charset_hi     ; bx = char set ptr:offset
  2054.     jmp     s @gpc_set_char     ; go setup character ptr
  2055.  
  2056. @gpc_lowchar:
  2057.  
  2058.     mov     ebx, charset_low    ; bx = char set ptr:offset
  2059.  
  2060. @gpc_set_char:
  2061.     and     eax, 07fh           ; mask out hi bits
  2062.     shl     ax, 3               ; * 8 bytes per bitmap
  2063.     add     ebx, eax            ; bx = offset of selected char
  2064.     mov     [ebp].gpc_t_sets, ebx ; save segment on stack
  2065.  
  2066.     and     cx, plane_bits      ; get plane #
  2067.     mov     ch, all_planes      ; get initial plane mask
  2068.     shl     ch, cl              ; and shift into position
  2069.     and     ch, all_planes      ; and mask to lower nibble
  2070.  
  2071.     mov     al, 04              ; 4-plane # = # of initial
  2072.     sub     al, cl              ; shifts to align bit mask
  2073.     mov     cl, al              ; shift count for shl
  2074.  
  2075. ;get segment of character map
  2076.  
  2077.     out_8   sc_index, map_mask  ; setup plane selections
  2078.     inc     dx                  ; dx -> sc_data
  2079.  
  2080.     mov     al, 08              ; 8 lines to process
  2081.     mov     [ebp].gpc_lines, al ; save on stack
  2082.  
  2083. @gpc_decode_char_byte:
  2084.  
  2085.     mov     esi, [ebp].gpc_t_sets ; get esi = string
  2086.  
  2087.     mov     bh, [esi]           ; get bit map
  2088.     inc     esi                 ; point to next line
  2089.     mov     [ebp].gpc_t_sets, esi ; and save new pointer...
  2090.  
  2091.     clr     eax                 ; clear ax
  2092.  
  2093.     clr     bl                      ; clear bl
  2094.     rol     bx, cl                  ; bl holds left edge bits
  2095.     movzx   esi, bx                 ; use as table index
  2096.     and     si, char_bits           ; get low bits
  2097.     mov     al, char_plane_data[esi] ; get mask in al
  2098.     jz      @gpc_no_left1bits       ; skip if no pixels to set
  2099.  
  2100.     mov     ah, [ebp].gpc_colorf ; get foreground color
  2101.     out     dx, al               ; set up screen mask
  2102.     mov     [edi], ah            ; write foreground color
  2103.  
  2104. @gpc_no_left1bits:
  2105.     xor     al, ch               ; invert mask for background
  2106.     jz      @gpc_no_left0bits    ; hey, no need for this
  2107.  
  2108.     mov     ah, [ebp].gpc_colorb ; get background color
  2109.     out     dx, al               ; set up screen mask
  2110.     mov     [edi], ah            ; write foreground color
  2111.  
  2112. ;now do middle/last band
  2113.  
  2114. @gpc_no_left0bits:
  2115.     inc     edi                 ; point to next byte
  2116.     rol     bx, 4               ; shift 4 bits
  2117.  
  2118.     movzx   esi, bx                 ; make lookup pointer
  2119.     and     si, char_bits           ; get low bits
  2120.     mov     al, char_plane_data[esi] ; get mask in al
  2121.     jz      @gpc_no_middle1bits     ; skip if no pixels to set
  2122.  
  2123.     mov     ah, [ebp].gpc_colorf ; get foreground color
  2124.     out     dx, al               ; set up screen mask
  2125.     mov     [edi], ah            ; write foreground color
  2126.  
  2127. @gpc_no_middle1bits:
  2128.     xor     al, all_planes       ; invert mask for background
  2129.     jz      @gpc_no_middle0bits  ; hey, no need for this
  2130.  
  2131.     mov     ah, [ebp].gpc_colorb ; get background color
  2132.     out     dx, al               ; set up screen mask
  2133.     mov     [edi], ah            ; write foreground color
  2134.  
  2135. @gpc_no_middle0bits:
  2136.     xor     ch, all_planes      ; invert clip mask
  2137.     cmp     cl, 4               ; aligned by 4?
  2138.     jz      @gpc_next_line      ; if so, exit now..
  2139.  
  2140.     inc     edi                 ; point to next byte
  2141.     rol     bx, 4               ; shift 4 bits
  2142.  
  2143.     movzx   esi, bx                 ; make lookup pointer
  2144.     and     si, char_bits           ; get low bits
  2145.     mov     al, char_plane_data[esi] ; get mask in al
  2146.     jz      @gpc_no_right1bits      ; skip if no pixels to set
  2147.  
  2148.     mov     ah, [ebp].gpc_colorf ; get foreground color
  2149.     out     dx, al               ; set up screen mask
  2150.     mov     [edi], ah            ; write foreground color
  2151.  
  2152. @gpc_no_right1bits:
  2153.  
  2154.     xor     al, ch               ; invert mask for background
  2155.     jz      @gpc_no_right0bits   ; hey, no need for this
  2156.  
  2157.     mov     ah, [ebp].gpc_colorb ; get background color
  2158.     out     dx, al               ; set up screen mask
  2159.     mov     [edi], ah            ; write foreground color
  2160.  
  2161. @gpc_no_right0bits:
  2162.     dec     edi                  ; adjust for next line advance
  2163.  
  2164. @gpc_next_line:
  2165.     add     edi, [ebp].gpc_width  ; point to next line
  2166.     xor     ch, char_bits       ; flip the clip mask back
  2167.  
  2168.     dec     [ebp].gpc_lines     ; count down lines
  2169.     jz      @gpc_exit           ; ok... done!
  2170.  
  2171.     jmp     @gpc_decode_char_byte   ; again! hey!
  2172.  
  2173. @gpc_exit:
  2174.     add     esp, 10             ; deallocate stack workspace
  2175.     pop     edi esi ebp         ; restore saved registers
  2176.     ret     10                  ; exit and clean up stack
  2177.  
  2178.     endif
  2179.     if x_tgprintc eq 1
  2180.  
  2181. ;==========================================
  2182. ;tgprintc (charnum%, xpos%, ypos%, colorf%)
  2183. ;==========================================
  2184. ;
  2185. ; transparently draws an ascii text character using the
  2186. ; currently selected 8x8 font on the active display page.
  2187. ;
  2188. ; entry: charnum = ascii character # to draw
  2189. ;        xpos    = x position to draw character at
  2190. ;        ypos    = y position of to draw character at
  2191. ;        colorf  = color to draw text character in
  2192. ;
  2193. ; exit:  no meaningful values returned
  2194. ;
  2195.  
  2196. tpc_stack   struc
  2197.     tpc_width   dd  ?   ; screen width-1
  2198.     tpc_lines   db  ?,? ; scan lines to decode
  2199.     tpc_t_sets  dd  ?   ; saved charset segment
  2200.                 dd  ?x3 ; edi, esi, ebp
  2201.                 dd  ?   ; caller
  2202.     tpc_colorf  db  ?,? ; text color
  2203.     tpc_ypos    dw  ?   ; y position to print at
  2204.     tpc_xpos    dw  ?   ; x position to print at
  2205.     tpc_char    db  ?,? ; character to print
  2206. tpc_stack   ends
  2207.  
  2208.         public tgprintc
  2209.  
  2210. tgprintc:
  2211.  
  2212.     push    ebp esi edi         ; preserve important registers
  2213.     sub     esp, 10             ; allocate workspace on stack
  2214.     mov     ebp, esp            ; set up stack frame
  2215.  
  2216.     mov     edi, current_page   ; point to active vga page
  2217.  
  2218.     movzx   eax, screen_width   ; get logical line width
  2219.     mov     ebx, eax            ; bx = screen width
  2220.     dec     bx                  ;    = screen width-1
  2221.     mov     [ebp].tpc_width,ebx ; save for later use
  2222.  
  2223.     mul     [ebp].tpc_ypos      ; start of line = ypos * width
  2224.     add     edi, eax            ; di -> start of line ypos
  2225.  
  2226.     movzx   eax, [ebp].tpc_xpos ; get xpos of character
  2227.     mov     cx, ax              ; save copy of xpos
  2228.     shr     ax, 2               ; bytes into line = xpos/4
  2229.     add     edi, eax            ; di -> (xpos, ypos)
  2230.  
  2231. ;get source addr of character bit map  & save
  2232.  
  2233.     mov     al, [ebp].tpc_char  ; get character #
  2234.     test    al, 080h            ; is hi bit set?
  2235.     jz      @tpc_lowchar        ; nope, use low char set ptr
  2236.  
  2237.     mov     ebx, charset_hi     ; bx = char set ptr:offset
  2238.     jmp     s @tpc_set_char     ; go setup character ptr
  2239.  
  2240. @tpc_lowchar:
  2241.  
  2242.     mov     ebx, charset_low    ; bx = char set ptr:offset
  2243.  
  2244. @tpc_set_char:
  2245.     and     eax, 07fh           ; mask out hi bits
  2246.     shl     ax, 3               ; * 8 bytes per bitmap
  2247.     add     ebx, eax            ; bx = offset of selected char
  2248.     mov     [ebp].tpc_t_sets, ebx ; save segment on stack
  2249.  
  2250.     and     cx, plane_bits      ; get plane #
  2251.     mov     ch, all_planes      ; get initial plane mask
  2252.     shl     ch, cl              ; and shift into position
  2253.     and     ch, all_planes      ; and mask to lower nibble
  2254.  
  2255.     mov     al, 04              ; 4-plane # = # of initial
  2256.     sub     al, cl              ; shifts to align bit mask
  2257.     mov     cl, al              ; shift count for shl
  2258.  
  2259. ;get segment of character map
  2260.  
  2261.     out_8   sc_index, map_mask  ; setup plane selections
  2262.     inc     dx                  ; dx -> sc_data
  2263.  
  2264.     mov     al, 08              ; 8 lines to process
  2265.     mov     [ebp].tpc_lines, al ; save on stack
  2266.  
  2267. @tpc_decode_char_byte:
  2268.  
  2269.     mov     esi, [ebp].tpc_t_sets ; get esi = string
  2270.  
  2271.     mov     bh, [esi]           ; get bit map
  2272.     inc     esi                 ; point to next line
  2273.     mov     [ebp].tpc_t_sets, esi ; and save new pointer...
  2274.  
  2275.     clr     eax                 ; clear ax
  2276.  
  2277.     clr     bl                      ; clear bl
  2278.     rol     bx, cl                  ; bl holds left edge bits
  2279.     movzx   esi, bx                 ; use as table index
  2280.     and     si, char_bits           ; get low bits
  2281.     mov     al, char_plane_data[esi] ; get mask in al
  2282.     jz      @tpc_no_left1bits       ; skip if no pixels to set
  2283.  
  2284.     mov     ah, [ebp].tpc_colorf ; get foreground color
  2285.     out     dx, al               ; set up screen mask
  2286.     mov     [edi], ah            ; write foreground color
  2287.  
  2288. ;now do middle/last band
  2289.  
  2290. @tpc_no_left1bits:
  2291.     inc     edi                 ; point to next byte
  2292.     rol     bx, 4               ; shift 4 bits
  2293.  
  2294.     movzx   esi, bx                 ; make lookup pointer
  2295.     and     si, char_bits           ; get low bits
  2296.     mov     al, char_plane_data[esi] ; get mask in al
  2297.     jz      @tpc_no_middle1bits     ; skip if no pixels to set
  2298.  
  2299.     mov     ah, [ebp].tpc_colorf ; get foreground color
  2300.     out     dx, al               ; set up screen mask
  2301.     mov     [edi], ah            ; write foreground color
  2302.  
  2303. @tpc_no_middle1bits:
  2304.     xor     ch, all_planes      ; invert clip mask
  2305.     cmp     cl, 4               ; aligned by 4?
  2306.     jz      @tpc_next_line      ; if so, exit now..
  2307.  
  2308.     inc     edi                 ; point to next byte
  2309.     rol     bx, 4               ; shift 4 bits
  2310.  
  2311.     movzx   esi, bx                 ; make lookup pointer
  2312.     and     si, char_bits           ; get low bits
  2313.     mov     al, char_plane_data[esi] ; get mask in al
  2314.     jz      @tpc_no_right1bits      ; skip if no pixels to set
  2315.  
  2316.     mov     ah, [ebp].tpc_colorf ; get foreground color
  2317.     out     dx, al               ; set up screen mask
  2318.     mov     [edi], ah            ; write foreground color
  2319.  
  2320. @tpc_no_right1bits:
  2321.     dec     edi                  ; adjust for next line advance
  2322.  
  2323. @tpc_next_line:
  2324.     add     edi, [ebp].tpc_width  ; point to next line
  2325.     xor     ch, char_bits       ; flip the clip mask back
  2326.  
  2327.     dec     [ebp].tpc_lines     ; count down lines
  2328.     jz      @tpc_exit           ; ok... done!
  2329.  
  2330.     jmp     @tpc_decode_char_byte   ; again! hey!
  2331.  
  2332. @tpc_exit:
  2333.     add     esp, 10             ; deallocate stack workspace
  2334.     pop     edi esi ebp         ; restore saved registers
  2335.     ret     8                   ; exit and clean up stack
  2336.  
  2337.     endif
  2338.     if x_gprintc eq 1
  2339.  
  2340. ;===============================================================
  2341. ;print_str (seg string, maxlen%, xpos%, ypos%, colorf%, colorb%)
  2342. ;===============================================================
  2343. ;
  2344. ; routine to quickly print a null terminated ascii string on the
  2345. ; active display page up to a maximum length.
  2346. ;
  2347. ; entry: string  = far pointer to ascii string to print
  2348. ;        maxlen  = # of characters to print if no null found
  2349. ;        xpos    = x position to draw text at
  2350. ;        ypos    = y position of to draw text at
  2351. ;        colorf  = color to draw text in
  2352. ;        colorb  = color to set background to
  2353. ;
  2354. ; exit:  no meaningful values returned
  2355. ;
  2356.  
  2357. ps_stack    struc
  2358.                 dd  ?x3 ; edi, esi, ebp
  2359.                 dd  ?   ; caller
  2360.     ps_colorb   dw  ?   ; background color
  2361.     ps_colorf   dw  ?   ; text color
  2362.     ps_ypos     dw  ?   ; y position to print at
  2363.     ps_xpos     dw  ?   ; x position to print at
  2364.     ps_len      dw  ?   ; maximum length of string to print
  2365.     ps_text     dd  ?   ; far ptr to text string
  2366. ps_stack    ends
  2367.  
  2368.         public  print_str
  2369.  
  2370. print_str:
  2371.  
  2372.     push    ebp esi edi         ; preserve important registers
  2373.     mov     ebp, esp            ; set up stack frame
  2374.  
  2375. @ps_print_it:
  2376.  
  2377.     mov     cx, [ebp].ps_len    ; get remaining text length
  2378.     jcxz    @ps_exit            ; exit when out of text
  2379.  
  2380.     mov     edi, [ebp].ps_text  ; edi -> current char in text
  2381.     mov     al, [edi]           ; al = text character
  2382.     and     ax, 00ffh           ; clear high word
  2383.     jz      @ps_exit            ; exit if null character
  2384.  
  2385.     dec     [ebp].ps_len        ; remaining text length--
  2386.     inc     [ebp].ps_text       ; point to next text char
  2387.  
  2388. ; set up call to gprintc
  2389.  
  2390.     push    ax                  ; set character parameter
  2391.     mov     bx, [ebp].ps_xpos   ; get xpos
  2392.     push    bx                  ; set xpos parameter
  2393.     add     bx, 8               ; advance 1 char to right
  2394.     mov     [ebp].ps_xpos, bx   ; save for next time through
  2395.  
  2396.     mov     bx, [ebp].ps_ypos   ; get ypos
  2397.     push    bx                  ; set ypos parameter
  2398.  
  2399.     mov     bx, [ebp].ps_colorf ; get text color
  2400.     push    bx                  ; set colorf parameter
  2401.  
  2402.     mov     bx, [ebp].ps_colorb ; get background color
  2403.     push    bx                  ; set colorb parameter
  2404.  
  2405.     call    gprintc             ; print character!
  2406.     jmp     s @ps_print_it      ; process next character
  2407.  
  2408. @ps_exit:
  2409.     pop     edi esi ebp         ; restore saved registers
  2410.     ret     14                  ; exit and clean up stack
  2411.  
  2412.     endif
  2413.     if x_tgprintc eq 1
  2414.  
  2415. ;================================================================
  2416. ;tprint_str (seg string, maxlen%, xpos%, ypos%, colorf%, colorb%)
  2417. ;================================================================
  2418. ;
  2419. ; routine to quickly transparently print a null terminated ascii
  2420. ; string on the active display page up to a maximum length.
  2421. ;
  2422. ; entry: string  = far pointer to ascii string to print
  2423. ;        maxlen  = # of characters to print if no null found
  2424. ;        xpos    = x position to draw text at
  2425. ;        ypos    = y position of to draw text at
  2426. ;        colorf  = color to draw text in
  2427. ;
  2428. ; exit:  no meaningful values returned
  2429. ;
  2430.  
  2431. tps_stack   struc
  2432.                 dd  ?x3 ; edi, esi, ebp
  2433.                 dd  ?   ; caller
  2434.     tps_colorf  dw  ?   ; text color
  2435.     tps_ypos    dw  ?   ; y position to print at
  2436.     tps_xpos    dw  ?   ; x position to print at
  2437.     tps_len     dw  ?   ; maximum length of string to print
  2438.     tps_text    dd  ?   ; far ptr to text string
  2439. tps_stack   ends
  2440.  
  2441.         public  tprint_str
  2442.  
  2443. tprint_str:
  2444.  
  2445.     push    ebp esi edi         ; preserve important registers
  2446.     mov     ebp, esp            ; set up stack frame
  2447.  
  2448. @ts_print_it:
  2449.  
  2450.     mov     cx, [ebp].tps_len   ; get remaining text length
  2451.     jcxz    @ts_exit            ; exit when out of text
  2452.  
  2453.     mov     edi, [ebp].tps_text ; edi -> current char in text
  2454.     mov     al, [edi]           ; al = text character
  2455.     and     ax, 00ffh           ; clear high word
  2456.     jz      @ts_exit            ; exit if null character
  2457.  
  2458.     dec     [ebp].tps_len       ; remaining text length--
  2459.     inc     [ebp].tps_text      ; point to next text char
  2460.  
  2461. ; set up call to tgprintc
  2462.  
  2463.     push    ax                  ; set character parameter
  2464.     mov     bx, [ebp].tps_xpos  ; get xpos
  2465.     push    bx                  ; set xpos parameter
  2466.     add     bx, 8               ; advance 1 char to right
  2467.     mov     [ebp].tps_xpos, bx  ; save for next time through
  2468.  
  2469.     mov     bx, [ebp].tps_ypos  ; get ypos
  2470.     push    bx                  ; set ypos parameter
  2471.  
  2472.     mov     bx, [ebp].tps_colorf ; get text color
  2473.     push    bx                  ; set colorf parameter
  2474.  
  2475.     call    tgprintc            ; print character!
  2476.     jmp     s @ts_print_it      ; process next character
  2477.  
  2478. @ts_exit:
  2479.     pop     edi esi ebp         ; restore saved registers
  2480.     ret     12                  ; exit and clean up stack
  2481.  
  2482.     endif
  2483.  
  2484. ;===========================================
  2485. ;set_display_font(seg fontdata, fontnumber%)
  2486. ;===========================================
  2487. ;
  2488. ; allows the user to specify their own font data for
  2489. ; wither the lower or upper 128 characters.
  2490. ;
  2491. ; entry: fontdata   = far pointer to font bitmaps
  2492. ;        fontnumber = which half of set this is
  2493. ;                   = 0, lower 128 characters
  2494. ;                   = 1, upper 128 characters
  2495. ;
  2496. ; exit:  no meaningful values returned
  2497. ;
  2498.  
  2499. sdf_stack   struc
  2500.                 dd  ?   ; ebp
  2501.                 dd  ?   ; caller
  2502.     sdf_which   dw  ?   ; hi table/low table flag
  2503.     sdf_font    dd  ?   ; far ptr to font table
  2504. sdf_stack   ends
  2505.  
  2506.     public  set_display_font
  2507.  
  2508. set_display_font:
  2509.  
  2510.     push    ebp                 ; preserve registers
  2511.     mov     ebp, esp            ; set up stack frame
  2512.  
  2513.     mov     edi, [ebp].sdf_font ; get far ptr to font
  2514.  
  2515.     mov     esi, o charset_low  ; assume lower 128 chars
  2516.     test    [ebp].sdf_which, 1  ; font #1 selected?
  2517.     jz      @sdf_set_font       ; if not, skip ahead
  2518.  
  2519.     mov     esi, o charset_hi   ; ah, really it's 128-255
  2520.  
  2521. @sdf_set_font:
  2522.     mov     [esi], edi          ; set font pointer offset
  2523.  
  2524.     pop     ebp                 ; restore registers
  2525.     ret     6                   ; we are done.. outa here
  2526.  
  2527. ; ===== bitmap (sprite) display routines =====
  2528.  
  2529. ;======================================================
  2530. ;draw_bitmap (seg image, xpos%, ypos% )
  2531. ;======================================================
  2532. ;
  2533. ; draws a variable sized graphics bitmap such as a
  2534. ; picture or an icon on the current display page in
  2535. ; mode x.  the bitmap is stored in a lifar byte array
  2536. ; corresponding to (0,0) (1,0), (2,0) .. (width, height)
  2537. ; this is the same lifar manner as mode 13h graphics.
  2538. ;
  2539. ; entry: image  = far pointer to bitmap data
  2540. ;        xpos   = x position to place upper left pixel at
  2541. ;        ypos   = y position to place upper left pixel at
  2542. ;        width  = width of the bitmap in pixels  - ommitted
  2543. ;        height = height of the bitmap in pixels - ommitted
  2544. ;
  2545. ; exit:  no meaningful values returned
  2546. ;
  2547. ; routine has been modified so that first two words of bitmap define
  2548. ; bitmap x and y size
  2549. ;
  2550.  
  2551. db_stack    struc
  2552.     db_lineo    dw  ?   ; offset to next line
  2553.     db_pixcount dw  ?   ; (minimum) # of pixels/line
  2554.     db_start    dd  ?   ; addr of upper left pixel
  2555.     db_pixskew  dw  ?   ; # of bytes to adjust eol
  2556.     db_skewflag dw  ?   ; extra pix on plane flag
  2557.     db_height   dw  ?   ; height of bitmap in pixels
  2558.                 dd  ?x3 ; edi, esi, ebp
  2559.                 dd  ?   ; caller
  2560.     db_ypos     dw  ?   ; y position to draw bitmap at
  2561.     db_xpos     dw  ?   ; x position to draw bitmap at
  2562.     db_image    dd  ?   ; far pointer to graphics bitmap
  2563. db_stack    ends
  2564.  
  2565.         public    draw_bitmap
  2566.  
  2567. draw_bitmap:
  2568.  
  2569.     push    ebp esi edi         ; preserve important registers
  2570.     sub     esp, 14             ; allocate workspace
  2571.     mov     ebp, esp            ; set up stack frame
  2572.  
  2573.     mov     edi, current_page   ; point to active vga page
  2574.     cld                         ; direction flag = forward
  2575.  
  2576.     movzx   eax, [ebp].db_ypos  ; get ul corner ypos
  2577.     mul     screen_width        ; ax = offset to line ypos
  2578.  
  2579.     movzx   ebx, [ebp].db_xpos  ; get ul corner xpos
  2580.     mov     cl, bl              ; save plane # in cl
  2581.     shr     bx, 2               ; xpos/4 = offset into line
  2582.  
  2583.     add     edi, eax            ; edi -> start of line
  2584.     add     edi, ebx            ; edi -> upper left pixel
  2585.     mov     [ebp].db_start, edi ; save starting addr
  2586.  
  2587. ; compute line to line offset
  2588.  
  2589.     mov     esi, [ebp].db_image ; esi-> source image
  2590.     lodsw                       ; get x width
  2591.     mov     bx,ax
  2592.     lodsw
  2593.     mov     [ebp].db_height,ax
  2594.     add     [ebp].db_image,4
  2595.  
  2596.     mov     dx, bx              ; save copy in dx
  2597.     shr     bx, 2               ; /4 = width in bands
  2598.     mov     ax, screen_width    ; get screen width
  2599.     sub     ax, bx              ; - (bitmap width/4)
  2600.  
  2601.     mov     [ebp].db_lineo, ax      ; save line width offset
  2602.     mov     [ebp].db_pixcount, bx   ; minimum # pix to copy
  2603.  
  2604.     and     dx, plane_bits          ; get "partial band" size (0-3)
  2605.     mov     [ebp].db_pixskew, dx    ; also end of line skew
  2606.     mov     [ebp].db_skewflag, dx   ; save as flag/count
  2607.  
  2608.     and     cx, plane_bits      ; cl = starting plane #
  2609.     mov     ax, map_mask_plane2 ; plane mask & plane select
  2610.     shl     ah, cl              ; select correct plane
  2611.     out_16  sc_index, ax        ; select plane...
  2612.     mov     bh, ah              ; bh = saved plane mask
  2613.     mov     bl, 4               ; bl = planes to copy
  2614.  
  2615. @db_copy_plane:
  2616.  
  2617.     mov     esi, [ebp].db_image ; esi-> source image
  2618.     mov     dx, [ebp].db_height ; # of lines to copy
  2619.     mov     edi, [ebp].db_start ; edi-> dest pos
  2620.  
  2621. @db_copy_line:
  2622.     mov     cx, [ebp].db_pixcount   ; min # to copy
  2623.  
  2624.     test    cl, 0fch            ; 16+pixwide?
  2625.     jz      @db_copy_remainder  ; nope...
  2626.  
  2627. ; pixel copy loop has been unrolled to x4
  2628.  
  2629. @db_copy_loop:
  2630.     movsb                       ; copy bitmap pixel
  2631.     add     esi, 3              ; skip to next byte in same plane
  2632.     movsb                       ; copy bitmap pixel
  2633.     add     esi, 3              ; skip to next byte in same plane
  2634.     movsb                       ; copy bitmap pixel
  2635.     add     esi, 3              ; skip to next byte in same plane
  2636.     movsb                       ; copy bitmap pixel
  2637.     add     esi, 3              ; skip to next byte in same plane
  2638.  
  2639.     sub     cl, 4               ; pixels to copy=-4
  2640.     test    cl, 0fch            ; 4+ pixels left?
  2641.     jnz     @db_copy_loop       ; if so, do another block
  2642.  
  2643. @db_copy_remainder:
  2644.     jcxz    @db_next_line       ; any pixels left on line
  2645.  
  2646. @db_copy2:
  2647.     movsb                       ; copy bitmap pixel
  2648.     add     esi,3               ; skip to next byte in same plane
  2649.     loopx   cx, @db_copy2       ; pixels to copy--, loop until done
  2650.  
  2651. @db_next_line:
  2652.  
  2653. ; any partial pixels? (some planes only)
  2654.  
  2655.     or      cx, [ebp].db_skewflag   ; get skew count
  2656.     jz      @db_next2               ; if no partial pixels
  2657.  
  2658.     movsb                       ; copy bitmap pixel
  2659.     dec     edi                 ; back up to align
  2660.     dec     esi                 ; back up to align
  2661.  
  2662. @db_next2:
  2663.     movzx   eax, [ebp].db_pixskew ; adjust skew
  2664.     add     esi, eax
  2665.     movzx   eax, [ebp].db_lineo   ; set to next display line
  2666.     add     edi, eax
  2667.     loopx   dx, @db_copy_line   ; lines to copy--, loop if more
  2668.  
  2669. ; copy next plane....
  2670.  
  2671.     dec     bl                  ; planes to go--
  2672.     jz      @db_exit            ; hey! we are done
  2673.  
  2674.     rol     bh, 1               ; next plane in line...
  2675.     out_8   sc_data, bh         ; select plane
  2676.  
  2677.     cmp     al, 12h             ; carry set if al=11h
  2678.     adc     [ebp].db_start, 0   ; screen addr =+carry
  2679.     inc     w [ebp].db_image    ; start @ next byte
  2680.  
  2681.     sub     [ebp].db_skewflag, 1 ; reduce planes to skew
  2682.     adc     [ebp].db_skewflag, 0 ; back to 0 if it was -1
  2683.  
  2684.     jmp     f @db_copy_plane    ; go copy the next plane
  2685.  
  2686. @db_exit:
  2687.     add     esp, 14             ; deallocate workspace
  2688.     pop     edi esi ebp         ; restore saved registers
  2689.     ret     8                   ; exit and clean up stack
  2690.  
  2691. ;=======================================================
  2692. ;tdraw_bitmap (seg image, xpos%, ypos%)
  2693. ;=======================================================
  2694. ;
  2695. ; transparently draws a variable sized graphics bitmap
  2696. ; such as a picture or an icon on the current display page
  2697. ; in mode x.  pixels with a value of 0 are not drawn,
  2698. ; leaving the previous "background" contents intact.
  2699. ;
  2700. ; the bitmap format is the same as for the draw_bitmap function.
  2701. ;
  2702. ; entry: image  = far pointer to bitmap data
  2703. ;        xpos   = x position to place upper left pixel at
  2704. ;        ypos   = y position to place upper left pixel at
  2705. ;        width  = width of the bitmap in pixels   - ommitted
  2706. ;        height = height of the bitmap in pixels  - ommitted
  2707. ;
  2708. ; exit:  no meaningful values returned
  2709. ;
  2710. ; routine has been modified so that first two words of bitmap define
  2711. ; bitmap x and y size
  2712. ;
  2713.  
  2714. tb_stack    struc
  2715.     tb_lineo    dw  ?   ; offset to next line
  2716.     tb_pixcount dw  ?   ; (minimum) # of pixels/line
  2717.     tb_start    dd  ?   ; addr of upper left pixel
  2718.     tb_pixskew  dw  ?   ; # of bytes to adjust eol
  2719.     tb_skewflag dw  ?   ; extra pix on plane flag
  2720.     tb_height   dw  ?   ; height of bitmap in pixels
  2721.                 dd  ?x3 ; edi, esi, ebp
  2722.                 dd  ?   ; caller
  2723.     tb_ypos     dw  ?   ; y position to draw bitmap at
  2724.     tb_xpos     dw  ?   ; x position to draw bitmap at
  2725.     tb_image    dd  ?   ; far pointer to graphics bitmap
  2726. tb_stack    ends
  2727.  
  2728.         public    tdraw_bitmap
  2729.  
  2730. tdraw_bitmap:
  2731.  
  2732.     push    ebp esi edi         ; preserve important registers
  2733.     sub     esp, 14             ; allocate workspace
  2734.     mov     ebp, esp            ; set up stack frame
  2735.  
  2736.     mov     edi, current_page   ; point to active vga page
  2737.     cld                         ; direction flag = forward
  2738.  
  2739.     movzx   eax, [ebp].tb_ypos  ; get ul corner ypos
  2740.     mul     screen_width        ; ax = offset to line ypos
  2741.  
  2742.     movzx   ebx, [ebp].tb_xpos  ; get ul corner xpos
  2743.     mov     cl, bl              ; save plane # in cl
  2744.     shr     bx, 2               ; xpos/4 = offset into line
  2745.  
  2746.     add     edi, eax            ; edi -> start of line
  2747.     add     edi, ebx            ; edi -> upper left pixel
  2748.     mov     [ebp].tb_start, edi ; save starting addr
  2749.  
  2750. ; compute line to line offset
  2751.  
  2752.     mov     esi, [ebp].tb_image ; esi-> source image
  2753.     lodsw                       ; get x width
  2754.     mov     bx,ax
  2755.     lodsw
  2756.     mov     [ebp].tb_height,ax
  2757.     add     [ebp].tb_image,4
  2758.  
  2759.     mov     dx, bx              ; save copy in dx
  2760.     shr     bx, 2               ; /4 = width in bands
  2761.     mov     ax, screen_width    ; get screen width
  2762.     sub     ax, bx              ; - (bitmap width/4)
  2763.  
  2764.     mov     [ebp].tb_lineo, ax      ; save line width offset
  2765.     mov     [ebp].tb_pixcount, bx   ; minimum # pix to copy
  2766.  
  2767.     and     dx, plane_bits          ; get "partial band" size (0-3)
  2768.     mov     [ebp].tb_pixskew, dx    ; also end of line skew
  2769.     mov     [ebp].tb_skewflag, dx   ; save as flag/count
  2770.  
  2771.     and     cx, plane_bits      ; cl = starting plane #
  2772.     mov     ax, map_mask_plane2 ; plane mask & plane select
  2773.     shl     ah, cl              ; select correct plane
  2774.     out_16  sc_index, ax        ; select plane...
  2775.     mov     bh, ah              ; bh = saved plane mask
  2776.     mov     bl, 4               ; bl = planes to copy
  2777.  
  2778. @tb_copy_plane:
  2779.  
  2780.     mov     esi, [ebp].tb_image  ; esi-> source image
  2781.     mov     dx, [ebp].tb_height  ; # of lines to copy
  2782.     mov     edi, [ebp].tb_start  ; edi-> dest pos
  2783.  
  2784. ; here ah is set with the value to be considered
  2785. ; "transparent".  it can be changed!
  2786.  
  2787. @tb_copy_line:
  2788.     mov     ah, 0               ; value to detect 0
  2789.     mov     cx, [ebp].tb_pixcount    ; min # to copy
  2790.  
  2791.     test    cl, 0fch            ; 16+pixwide?
  2792.     jz      @tb_copy_remainder  ; nope...
  2793.  
  2794. ; pixel copy loop has been unrolled to x4
  2795.  
  2796. @tb_copy_loop:
  2797.     lodsb                       ; get pixel value in al
  2798.     add     esi, 3              ; skip to next byte in same plane
  2799.     cmp     al, ah              ; it is "transparent"?
  2800.     je      @tb_skip_01         ; skip ahead if so
  2801.     mov     [edi], al           ; copy pixel to vga screen
  2802.  
  2803. @tb_skip_01:
  2804.     lodsb                       ; get pixel value in al
  2805.     add     esi, 3              ; skip to next byte in same plane
  2806.     cmp     al, ah              ; it is "transparent"?
  2807.     je      @tb_skip_02         ; skip ahead if so
  2808.     mov     [edi+1], al         ; copy pixel to vga screen
  2809.  
  2810. @tb_skip_02:
  2811.     lodsb                       ; get pixel value in al
  2812.     add     esi, 3              ; skip to next byte in same plane
  2813.     cmp     al, ah              ; it is "transparent"?
  2814.     je      @tb_skip_03         ; skip ahead if so
  2815.     mov     [edi+2], al         ; copy pixel to vga screen
  2816.  
  2817. @tb_skip_03:
  2818.     lodsb                       ; get pixel value in al
  2819.     add     esi, 3              ; skip to next byte in same plane
  2820.     cmp     al, ah              ; it is "transparent"?
  2821.     je      @tb_skip_04         ; skip ahead if so
  2822.     mov     [edi+3], al         ; copy pixel to vga screen
  2823.  
  2824. @tb_skip_04:
  2825.     add     edi, 4              ; adjust pixel write location
  2826.     sub     cl, 4               ; pixels to copy=-4
  2827.     test    cl, 0fch            ; 4+ pixels left?
  2828.     jnz     @tb_copy_loop       ; if so, do another block
  2829.  
  2830. @tb_copy_remainder:
  2831.     jcxz    @tb_next_line       ; any pixels left on line
  2832.  
  2833. @tb_copy2:
  2834.     lodsb                       ; get pixel value in al
  2835.     add     esi, 3              ; skip to next byte in same plane
  2836.     cmp     al, ah              ; it is "transparent"?
  2837.     je      @tb_skip_05         ; skip ahead if so
  2838.     mov     [edi], al           ; copy pixel to vga screen
  2839.  
  2840. @tb_skip_05:
  2841.     inc     edi                 ; advance dest addr
  2842.     loopx   cx, @tb_copy2       ; pixels to copy--, loop until done
  2843.  
  2844. @tb_next_line:
  2845.  
  2846. ; any partial pixels? (some planes only)
  2847.  
  2848.     or      cx, [ebp].tb_skewflag   ; get skew count
  2849.     jz      @tb_next2               ; if no partial pixels
  2850.  
  2851.     lodsb                       ; get pixel value in al
  2852.     dec     esi                 ; backup to align
  2853.     cmp     al, ah              ; it is "transparent"?
  2854.     je      @tb_next2           ; skip ahead if so
  2855.     mov     [edi], al           ; copy pixel to vga screen
  2856.  
  2857. @tb_next2:
  2858.     movzx   eax, [ebp].tb_pixskew ; adjust skew
  2859.     add     esi, eax
  2860.     movzx   eax, [ebp].tb_lineo   ; set to next display line
  2861.     add     edi, eax
  2862.     loopx   dx, @tb_copy_line   ; lines to copy--, loop if more
  2863.  
  2864.     ;copy next plane....
  2865.  
  2866.     dec     bl                  ; planes to go--
  2867.     jz      @tb_exit            ; hey! we are done
  2868.  
  2869.     rol     bh, 1               ; next plane in line...
  2870.     out_8   sc_data, bh         ; select plane
  2871.  
  2872.     cmp     al, 12h             ; carry set if al=11h
  2873.     adc     [ebp].tb_start, 0   ; screen addr =+carry
  2874.     inc     w [ebp].tb_image    ; start @ next byte
  2875.  
  2876.     sub     [ebp].tb_skewflag, 1 ; reduce planes to skew
  2877.     adc     [ebp].tb_skewflag, 0 ; back to 0 if it was -1
  2878.  
  2879.     jmp     @tb_copy_plane      ; go copy the next plane
  2880.  
  2881. @tb_exit:
  2882.     add     esp, 14             ; deallocate workspace
  2883.     pop     edi esi ebp         ; restore saved registers
  2884.     ret     8                   ; exit and clean up stack
  2885.  
  2886. ; ==== video memory to video memory copy routines =====
  2887.  
  2888. ;==================================
  2889. ;copy_page (sourcepage%, destpage%)
  2890. ;==================================
  2891. ;
  2892. ; duplicate on display page onto another
  2893. ;
  2894. ; entry: sourcepage = display page # to duplicate
  2895. ;        destpage   = display page # to hold copy
  2896. ;
  2897. ; exit:  no meaningful values returned
  2898. ;
  2899.  
  2900. cp_stack    struc
  2901.                 dd  ?x3 ; edi, esi, ebp
  2902.                 dd  ?   ; caller
  2903.     cp_destp    dw  ?   ; page to hold copied image
  2904.     cp_sourcep  dw  ?   ; page to make copy from
  2905. cp_stack    ends
  2906.  
  2907.         public    copy_page
  2908.  
  2909. copy_page:
  2910.  
  2911.     push    ebp esi edi         ; preserve important registers
  2912.     mov     ebp, esp            ; set up stack frame
  2913.     cld                         ; block xfer forwards
  2914.  
  2915. ; make sure page #'s are valid
  2916.  
  2917.     mov     ax, [ebp].cp_sourcep ; get source page #
  2918.     cmp     ax, last_page       ; is it > max page #?
  2919.     jae     @cp_exit            ; if so, abort
  2920.  
  2921.     mov     bx, [ebp].cp_destp  ; get destination page #
  2922.     cmp     bx, last_page       ; is it > max page #?
  2923.     jae     @cp_exit            ; if so, abort
  2924.  
  2925.     cmp     ax, bx              ; pages #'s the same?
  2926.     je      @cp_exit            ; if so, abort
  2927.  
  2928. ; setup esi and edi to video pages
  2929.  
  2930.     shl     bx, 2               ; scale index to dword
  2931.     mov     edi, page_addr[ebx] ; offset to dest page
  2932.  
  2933.     mov     bx, ax              ; index to source page
  2934.     shl     bx, 2               ; scale index to dword
  2935.     mov     esi, page_addr[ebx] ; offset to source page
  2936.  
  2937.     movzx   ecx, page_size      ; get size of page
  2938.  
  2939. ; setup vga registers for mem to mem copy
  2940.  
  2941.     out_16  gc_index, latches_on    ; data from latches = on
  2942.     out_16  sc_index, all_planes_on ; copy all planes
  2943.  
  2944. ; note.. do *not* use movsw or movsd - they will
  2945. ; screw with the latches which are 8 bits x 4
  2946.  
  2947.     rep     movsb               ; copy entire page!
  2948.  
  2949. ; reset vga for normal memory access
  2950.  
  2951.     out_16  gc_index, latches_off   ; data from latches = off
  2952.  
  2953. @cp_exit:
  2954.     pop     edi esi ebp         ; restore saved registers
  2955.     ret     4                   ; exit and clean up stack
  2956.  
  2957. ;==========================================================================
  2958. ;copy_bitmap (sourcepage%, x1%, y1%, x2%, y2%, destpage%, destx1%, desty1%)
  2959. ;==========================================================================
  2960. ;
  2961. ; copies a bitmap image from one display page to another
  2962. ; this routine is limited to copying images with the same
  2963. ; plane alignment.  to work: (x1 mod 4) must = (destx1 mod 4)
  2964. ; copying an image to the same page is supported, but results
  2965. ; may be defined when the when the rectangular areas
  2966. ; (x1, y1) - (x2, y2) and (destx1, desty1) -
  2967. ; (destx1+(x2-x1), desty1+(y2-y1)) overlap...
  2968. ; no paramter checking to done to insure that
  2969. ; x2 >= x1 and y2 >= y1.  be careful...
  2970. ;
  2971. ; entry: sourcepage = display page # with source image
  2972. ;        x1         = upper left xpos of source image
  2973. ;        y1         = upper left ypos of source image
  2974. ;        x2         = lower right xpos of source image
  2975. ;        y2         = lower right ypos of source image
  2976. ;        destpage   = display page # to copy image to
  2977. ;        destx1     = xpos to copy ul corner of image to
  2978. ;        desty1     = ypos to copy ul corner of image to
  2979. ;
  2980. ; exit:  ax = success flag:   0 = failure / -1= success
  2981. ;
  2982.  
  2983. cb_stack    struc
  2984.     cb_height   dw  ?   ; height of image in lines
  2985.     cb_width    dw  ?   ; width of image in "bands"
  2986.                 dd  ?x3 ; edi, esi, ebp
  2987.                 dd  ?   ; caller
  2988.     cb_desty1   dw  ?   ; destination ypos
  2989.     cb_destx1   dw  ?   ; destination xpos
  2990.     cb_destp    dw  ?   ; page to copy bitmap to
  2991.     cb_y2       dw  ?   ; lr ypos of image
  2992.     cb_x2       dw  ?   ; lr xpos of image
  2993.     cb_y1       dw  ?   ; ul ypos of image
  2994.     cb_x1       dw  ?   ; ul xpos of image
  2995.     cb_sourcep  dw  ?   ; page containing source bitmap
  2996. cb_stack    ends
  2997.  
  2998.         public    copy_bitmap
  2999.  
  3000. copy_bitmap:
  3001.  
  3002.     push    ebp esi edi         ; preserve important registers
  3003.     sub     esp, 4              ; allocate workspace on stack
  3004.     mov     ebp, esp            ; set up stack frame
  3005.  
  3006. ; prep registers (and keep jumps short!)
  3007.  
  3008.     cld                         ; block xfer forwards
  3009.  
  3010. ; make sure parameters are valid
  3011.  
  3012.     movzx   ebx, [ebp].cb_sourcep ; get source page #
  3013.     cmp     bx, last_page       ; is it > max page #?
  3014.     jae     @cb_abort           ; if so, abort
  3015.  
  3016.     mov     cx, [ebp].cb_destp  ; get destination page #
  3017.     cmp     cx, last_page       ; is it > max page #?
  3018.     jae     @cb_abort           ; if so, abort
  3019.  
  3020.     mov     ax, [ebp].cb_x1     ; get source x1
  3021.     xor     ax, [ebp].cb_destx1 ; compare bits 0-1
  3022.     and     ax, plane_bits      ; check plane bits
  3023.     jnz     @cb_abort           ; they should cancel out
  3024.  
  3025. ; setup for copy processing
  3026.  
  3027.     out_8   sc_index, map_mask      ; set up for plane select
  3028.     out_16  gc_index, latches_on    ; data from latches = on
  3029.  
  3030. ; compute info about images, setup esi & edi
  3031.  
  3032.     mov     ax, [ebp].cb_y2     ; height of bitmap in lines
  3033.     sub     ax, [ebp].cb_y1     ; is y2 - y1 + 1
  3034.     inc     ax                  ; (add 1 since were not 0 based)
  3035.     mov     [ebp].cb_height, ax ; save on stack for later use
  3036.  
  3037.     mov     ax, [ebp].cb_x2     ; get # of "bands" of 4 pixels
  3038.     mov     dx, [ebp].cb_x1     ; the bitmap occupies as x2-x1
  3039.     shr     ax, 2               ; get x2 band (x2 / 4)
  3040.     shr     dx, 2               ; get x1 band (x1 / 4)
  3041.     sub     ax, dx              ; ax = # of bands - 1
  3042.     inc     ax                  ; ax = # of bands
  3043.     mov     [ebp].cb_width, ax  ; save on stack for later use
  3044.  
  3045.     shl     bx, 2               ; scale source page to dword
  3046.     mov     esi, page_addr[ebx] ; si = offset of source page
  3047.     mov     ax, [ebp].cb_y1     ; get source y1 line
  3048.     mul     screen_width        ; ax = offset to line y1
  3049.     movzx   eax, ax
  3050.     add     esi, eax            ; si = offset to line y1
  3051.     mov     ax, [ebp].cb_x1     ; get source x1
  3052.     shr     ax, 2               ; x1 / 4 = byte offset
  3053.     add     esi, eax            ; si = byte offset to (x1,y1)
  3054.  
  3055.     mov     bx, cx              ; dest page index to bx
  3056.     shl     bx, 2               ; scale source page to dword
  3057.     mov     edi, page_addr[ebx] ; di = offset of dest page
  3058.     mov     ax, [ebp].cb_desty1 ; get dest y1 line
  3059.     mul     screen_width        ; ax = offset to line y1
  3060.     movzx   eax, ax
  3061.     add     edi, eax            ; di = offset to line y1
  3062.     mov     ax, [ebp].cb_destx1 ; get dest x1
  3063.     shr     ax, 2               ; x1 / 4 = byte offset
  3064.     add     edi, eax            ; di = byte offset to (d-x1,d-y1)
  3065.  
  3066.     mov     cx, [ebp].cb_width  ; cx = width of image (bands)
  3067.     dec     cx                  ; cx = 1?
  3068.     je      @cb_only_one_band   ; 0 means image width of 1 band
  3069.  
  3070.     mov     bx, [ebp].cb_x1     ; get source x1
  3071.     and     bx, plane_bits      ; aligned? (bits 0-1 = 00?)
  3072.     jz      @cb_check_right     ; if so, check right alignment
  3073.     jnz     @cb_left_band       ; not aligned? well..
  3074.  
  3075. @cb_abort:
  3076.     clr     ax                  ; return false (failure)
  3077.     jmp     @cb_exit            ; and finish up
  3078.  
  3079. ; copy when left & right clip masks overlap...
  3080.  
  3081. @cb_only_one_band:
  3082.     mov     bx, [ebp].cb_x1         ; get left clip mask
  3083.     and     bx, plane_bits          ; mask out row #
  3084.     mov     al, left_clip_mask[ebx] ; get left edge mask
  3085.     mov     bx, [ebp].cb_x2         ; get right clip mask
  3086.     and     bx, plane_bits          ; mask out row #
  3087.     and     al, right_clip_mask[ebx] ; get right edge mask byte
  3088.  
  3089.     out_8   sc_data, al         ; clip for left & right masks
  3090.  
  3091.     mov     cx, [ebp].cb_height ; cx = # of lines to copy
  3092.     movzx   edx, screen_width   ; dx = width of screen
  3093.     clr     ebx                 ; bx = offset into image
  3094.  
  3095. @cb_one_loop:
  3096.     mov     al, [esi+ebx]       ; load latches
  3097.     mov     [edi+ebx], al       ; unload latches
  3098.     add     bx, dx              ; advance offset to next line
  3099.     loopjz  cx, @cb_one_done    ; exit loop if finished
  3100.  
  3101.     mov     al, [esi+ebx]       ; load latches
  3102.     mov     [edi+ebx], al       ; unload latches
  3103.     add     bx, dx              ; advance offset to next line
  3104.     loopx   cx, @cb_one_loop    ; loop until finished
  3105.  
  3106. @cb_one_done:
  3107.     jmp     @cb_finish          ; outa here!
  3108.  
  3109. ; copy left edge of bitmap
  3110.  
  3111. @cb_left_band:
  3112.  
  3113.     out_8   sc_data, left_clip_mask[ebx] ; set left edge plane mask
  3114.  
  3115.     mov     cx, [ebp].cb_height ; cx = # of lines to copy
  3116.     mov     dx, screen_width    ; dx = width of screen
  3117.     clr     ebx                 ; bx = offset into image
  3118.  
  3119. @cb_left_loop:
  3120.     mov     al, [esi+ebx]       ; load latches
  3121.     mov     [edi+ebx], al       ; unload latches
  3122.     add     bx, dx              ; advance offset to next line
  3123.     loopjz  cx, @cb_left_done   ; exit loop if finished
  3124.  
  3125.     mov     al, [esi+ebx]       ; load latches
  3126.     mov     [edi+ebx], al       ; unload latches
  3127.     add     bx, dx              ; advance offset to next line
  3128.     loopx   cx, @cb_left_loop   ; loop until finished
  3129.  
  3130. @cb_left_done:
  3131.     inc     edi                 ; move dest over 1 band
  3132.     inc     esi                 ; move source over 1 band
  3133.     dec     [ebp].cb_width      ; band width--
  3134.  
  3135. ; determine if right edge of bitmap needs special copy
  3136.  
  3137. @cb_check_right:
  3138.     mov     bx, [ebp].cb_x2     ; get source x2
  3139.     and     bx, plane_bits      ; aligned? (bits 0-1 = 11?)
  3140.     cmp     bl, 03h             ; plane = 3?
  3141.     je      @cb_copy_middle     ; copy the middle then!
  3142.  
  3143. ; copy right edge of bitmap
  3144.  
  3145. @cb_right_band:
  3146.  
  3147.     out_8   sc_data, right_clip_mask[ebx]  ; set right edge plane mask
  3148.  
  3149.     dec     [ebp].cb_width      ; band width--
  3150.     mov     cx, [ebp].cb_height ; cx = # of lines to copy
  3151.     mov     dx, screen_width    ; dx = width of screen
  3152.     movzx   ebx, [ebp].cb_width ; bx = offset to right edge
  3153.  
  3154. @cb_right_loop:
  3155.     mov     al, [esi+ebx]       ; load latches
  3156.     mov     [edi+ebx], al       ; unload latches
  3157.     add     bx, dx              ; advance offset to next line
  3158.     loopjz  cx, @cb_right_done  ; exit loop if finished
  3159.  
  3160.     mov     al, [esi+ebx]       ; load latches
  3161.     mov     [edi+ebx], al       ; unload latches
  3162.     add     bx, dx              ; advance offset to next line
  3163.     loopx   cx, @cb_right_loop  ; loop until finished
  3164.  
  3165. @cb_right_done:
  3166.  
  3167. ; copy the main block of the bitmap
  3168.  
  3169. @cb_copy_middle:
  3170.  
  3171.     mov     cx, [ebp].cb_width  ; get width remaining
  3172.     jcxz    @cb_finish          ; exit if done
  3173.  
  3174.     out_8   sc_data, all_planes ; copy all planes
  3175.  
  3176.     mov     dx, screen_width    ; get width of screen minus
  3177.     sub     dx, cx              ; image width (for adjustment)
  3178.     movzx   edx, dx
  3179.     mov     ax, [ebp].cb_height ; ax = # of lines to copy
  3180.     movzx   ecx,cx
  3181.     mov     ebx, ecx            ; bx = quick rep reload count
  3182.  
  3183. ; actual copy loop.  rep movsb does the work
  3184.  
  3185. @cb_middle_copy:
  3186.     mov     ecx, ebx            ; recharge rep count
  3187.     rep     movsb               ; move bands
  3188.     loopjz  ax, @cb_finish      ; exit loop if finished
  3189.  
  3190.     add     esi, edx            ; adjust esi to next line
  3191.     add     edi, edx            ; adjust edi to next line
  3192.  
  3193.     mov     ecx, ebx            ; recharge rep count
  3194.     rep     movsb               ; move bands
  3195.  
  3196.     add     esi, edx            ; adjust esi to next line
  3197.     add     edi, edx            ; adjust edi to next line
  3198.     loopx   ax, @cb_middle_copy ; copy lines until done
  3199.  
  3200. @cb_finish:
  3201.     out_16  gc_index, latches_off   ; data from latches = on
  3202.  
  3203. @cb_exit:
  3204.     add     esp, 4              ; deallocate stack workspace
  3205.     pop     edi esi ebp         ; restore saved registers
  3206.     ret     16                  ; exit and clean up stack
  3207.  
  3208. ; return to mode 03 before exiting to dos
  3209.  
  3210.         public mode03
  3211.  
  3212. mode03:
  3213.         mov v86r_ax,3h
  3214.         mov al,10h
  3215.         int 33h
  3216.         ret
  3217.  
  3218. fb_stack    struc
  3219.     fb_add      dw  ?
  3220.     fb_count    dd  ?
  3221.                 dd  ?x3 ; edi, esi, ebp
  3222.                 dd  ?   ; caller
  3223.     fb_pal      dd  ?   ; source palette
  3224. fb_stack    ends
  3225.  
  3226.         public wipeoffpalette
  3227.         public fadeoffpalette
  3228.         public fadeonpalette
  3229.  
  3230. ; load esi to palette
  3231.  
  3232. tmppal  db 768 dup (0)
  3233.  
  3234. wipeoffpalette:
  3235.         xor     al,al   ; wipe palette, clear all to r0,g0,b0
  3236.         mov     dx,3c8h
  3237.         out     dx,al
  3238.         inc     dx
  3239.         mov     cx,768
  3240.         xor     al,al
  3241.  
  3242. wipeit: out     dx,al
  3243.         loop    wipeit
  3244.  
  3245.         ret
  3246.  
  3247. fadeoffpalette:
  3248.         mov     bh, 2               ; bh = step
  3249.         mov     ah,0                ; ah = starting subtact
  3250.         jmp     fadepalette
  3251.  
  3252. fadeonpalette:
  3253.         mov     bh,-2
  3254.         mov     ah,64
  3255.  
  3256. fadepalette:
  3257.         push    ebp esi edi         ; preserve important registers
  3258.         sub     esp, 6
  3259.         mov     ebp, esp            ; set up stack frame
  3260.         mov     ecx,32
  3261.         cld                         ; block xfer forwards
  3262. fonp2:
  3263.         mov     esi,[ebp].fb_pal
  3264.         mov     [ebp].fb_add,ax
  3265.         mov     [ebp].fb_count,ecx
  3266.  
  3267.         mov     edi,offset tmppal
  3268.         mov     ecx,768
  3269.  
  3270. fonp1:
  3271.         lodsb
  3272.         sub     al,ah
  3273.         jnc     fonp3
  3274.         xor     al,al
  3275. fonp3:
  3276.         stosb
  3277.         loop    fonp1
  3278.  
  3279.         call    sync_display
  3280.         mov     dx,3c8h
  3281.         mov     esi,offset tmppal
  3282.         mov     ecx,768/6
  3283.         xor     al,al
  3284.         out     dx,al
  3285.         inc     dx
  3286.  
  3287. fonp4:
  3288.         lodsb
  3289.         out     dx,al
  3290.         lodsb
  3291.         out     dx,al
  3292.         lodsb
  3293.         out     dx,al
  3294.         lodsb
  3295.         out     dx,al
  3296.         lodsb
  3297.         out     dx,al
  3298.         lodsb
  3299.         out     dx,al
  3300.         loop    fonp4
  3301.  
  3302.         call    sync_display
  3303.  
  3304.         mov     ecx,[ebp].fb_count
  3305.         mov     ax,[ebp].fb_add
  3306.         add     ah,bh
  3307.         loop    fonp2
  3308.  
  3309.         add     esp,6
  3310.         pop     edi esi ebp
  3311.  
  3312.         ret     4
  3313.  
  3314.         public turn_screen_off
  3315.         public turn_screen_on
  3316.  
  3317. turn_screen_off:           ; guess what these do!
  3318.         mov dx,03dah       ; these are used when changing video modes
  3319.         in al,dx           ; to avoid any flicker
  3320.         mov dx,03c0h
  3321.         mov al,0
  3322.         out dx,al
  3323.         ret
  3324.  
  3325. turn_screen_on:
  3326.         mov dx,03dah
  3327.         in al,dx
  3328.         mov dx,03c0h
  3329.         mov al,20h
  3330.         out dx,al
  3331.         ret
  3332.  
  3333. code32  ends
  3334.         end
  3335.